home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Pascal / Snippets / CopyBits Demo / CopyBitsDemo.p < prev    next >
Encoding:
Text File  |  1995-10-22  |  77.7 KB  |  2,318 lines  |  [TEXT/MWPS]

  1. {
  2. { CopyBits Demo.p
  3. {
  4. { Implemented in Oct 1995 using Metrowerks CW6.
  5. { Converted from C code written in May 1995 using 
  6. { Metrowerks CodeWarrior v5.
  7. {
  8. { This Pascal CopyBits Demo project v3.1P is by Bill Catambay.
  9. { The orginal C CopyBits Demo project v3.1 was by Kenneth Worley.
  10. {
  11. { This code is Copyright 1995. All Rights Reserved.
  12. { You may use this code in any project of your own. You may also
  13. { redistribute this project to anyone else as long as 1) all the
  14. { project files (including documentation files) are kept together,
  15. { and 2) nothing is charged for the project.
  16. {
  17. { I really don't know what the rules are for C code converted to
  18. { Pascal as far as permission, licensing, and all that garbage.
  19. { If you have any information to shed light on this subject for me,
  20. { please E-mail me at Catambay@aol.com (and I thank you in advance).
  21. {
  22. {Worley notes:
  23. { This is a tutorial project that demonstrates the use of
  24. { CopyBits and offscreen Graphics Worlds (GWorlds). It shows
  25. { several instances of copying images to and from offscreen
  26. { graphics worlds using CopyBits, provides several macros that
  27. { make the process a little easier, shows an example of
  28. { drawing into an offscreen graphics world and how that can
  29. { improve onscreen animation, and it demonstrates a "fade"
  30. { using CopyBits to fade a portion of the screen to black.
  31. {
  32. { In a nutshell, the app puts up a dialog that shows two
  33. { "source" pictures (1 & 2) and a destination area. Clicking
  34. { on the "Copy" buttons above each of the source pictures
  35. { causes the picture to be copied to the destination area.
  36. { Picture 1 is labelled as "flickery animation" and picture 2
  37. { is labelled as "smooth animation." When you put the cursor
  38. { over each picture, you should see a difference in how a
  39. { colored circle is animated over the picture. You should
  40. { occasionally see the background "flicker" through on
  41. { picture 1, but not on picture 2 because it uses an
  42. { intermediary GWorld to draw in.
  43. {
  44. { The Fade to black button over the destination area will
  45. { cause that area to fade to black from whatever happens to
  46. { be in there. It does this by repeatedly copying a gray
  47. { rectangle from a GWorld into the destination area using
  48. { the subPin transfer mode of CopyBits. The erase button
  49. { erases the destination area.
  50. {
  51. { The Fade picture buttons cause the picture under the
  52. { button to be faded into whatever is currently in the
  53. { destination area. This is accomplished using CopyBits'
  54. { blend transfer mode.
  55. {
  56. {Conversion notes:
  57. {   Of course, all the standard C to Pascal translation stuff
  58. {   applies.  Additionally, there are some pointer stuff I had to
  59. {   tweak to get this working in Pascal.  I also had to play with
  60. {   the RGBColor records sometimes, because in Pascal they are treated
  61. {   as integers, but in C they are treated as unsigned (I'm talking
  62. {   about the components of course).  
  63. {
  64. {   Here's as example of C to Pascal translation which fuels my love for Pascal:
  65. {
  66. { As originally done in C:
  67. {    LocalToGlobal(* (Point*) &(offscreenRect.top));
  68. {    LocalToGlobal(* (Point*) &(offscreenRect.bottom));
  69. {
  70. { As translated into Pascal:
  71. {    LocalToGlobal(offscreenRect.topleft);
  72. {    LocalToGlobal(offscreenRect.botRight);
  73. {
  74. { Got rid of most of the C macros, converting just one of them, WinBitMap,
  75. { into a pascal function.  Also converted to pascal are three other 
  76. { C libraries.  They have been implemented as UNITs: MyAlerts, MyDialogUtils,
  77. { and MySystemUtils.  And there was some other stuff I had to do to get 
  78. { this working, but I'm too tired now to try and remember it all.  Just enjoy
  79. { the code, and I hope you learn lots of stuff!
  80. {
  81. { Questions? Comments? Praise? Criticism? Jobs? If it has
  82. { to do with the Pascal code included here, write to 
  83. { Bill Catambay at catambay@aol.com, and if it has to do with
  84. { the original C code, write to Kenneth Worley at KNEworley@aol.com.
  85. }
  86. Program CopyBitsDemo;
  87.  
  88. Uses
  89.     QDOffscreen, Dialogs, PictUtils, SegLoad, ToolUtils, DiskInit,
  90.     MyAlerts, MyDialogUtils, MySystemUtils;
  91.  
  92. Const
  93.     { The main dialog's resource ID. }
  94.     kMainDlgID    = 128;
  95.     { The two pictures in the main dialog. }
  96.     kPict1ID    = 128;
  97.     kPict2ID    = 129;
  98.     { Item numbers in the main dialog. }
  99.     kMainDlgQuit             = 1;
  100.     kMainDlgCopyOne         = 2;
  101.     kMainDlgFadeOne            = 3;
  102.     kMainDlgCopyTwo            = 4;
  103.     kMainDlgFadeTwo            = 5;
  104.     kMainDlgErase            = 6;
  105.     kMainDlgPICTOne            = 8;
  106.     kMainDlgPICTTwo            = 9;
  107.     kMainDlgDestPICT        = 10;
  108.     kMainDlgFadeSpeed        = 15;
  109.     kMainDlgFullScreen        = 20;
  110.     kMainDlgPixelize        = 21;
  111.     kMainDlgDepixelizeOne    = 22;
  112.     kMainDlgDepixelizeTwo    = 23;
  113.     kMainDlgFadeToBlack1    = 7;
  114.     kMainDlgFadeToBlack2    = 24;
  115.     kMainDlgFadeToBlack3    = 25;
  116.     kMainDlgBlur            = 27;
  117.     kMainDlgFlipHoriz        = 29;
  118.     kMainDlgFlipVert        = 30;
  119.     kMainDlgSlideL            = 34;
  120.     kMainDlgSlideR            = 35;
  121.     kMainDlgSlideT            = 36;
  122.     kMainDlgSlideB            = 37;
  123.     kMainDlgApertureIn        = 32;
  124.     kMainDlgApertureOut        = 38;
  125.     kMainDlgTechDemo        = 39;
  126.     { The CopyBits Technical Demo dialog ID. }
  127.     kTechDemoDlgID            = 130;
  128.     { Item numbers in the Technical Demo dialog. }
  129.     kTechDemoSourceFirst    = 10;
  130.     kTechDemoSourceLast        = 14;
  131.     kTechDemoMaskFirst        = 15;
  132.     kTechDemoMaskLast        = 18;
  133.     kTechDemoModeFirst        = 21;
  134.     kTechDemoModeLast        = 36;
  135.     kTechDemoDither            = 37;
  136.     kTechDemoHilite            = 38;
  137.     kTechDemoOpColorFirst    = 42;
  138.     kTechDemoOpColorLast    = 46;
  139.     kTechDemoDestPict        = 9;
  140.     kTechDemoCopyBits        = 49;
  141.     kTechDemoCopyMask        = 50;
  142.     kTechDemoDone            = 51;
  143.     kTechDemoSourcePict1    = 1;
  144.     kTechDemoSourcePict2    = 2;
  145.     kTechDemoSourcePict3    = 3;
  146.     kTechDemoSourcePict4    = 4;
  147.     kTechDemoSourcePict5    = 5;
  148.     kTechDemoMaskPict1        = 6;
  149.     kTechDemoMaskPict2        = 7;
  150.     kTechDemoMaskPict3        = 8;
  151.     kTechDemoMaskNone        = 53;
  152.     kTechDemoOpColorPict    = 40;
  153.     kTechDemoErase            = 54;
  154.     kTechDemoCopyDeepMask    = 55;
  155.     kTechDemoMaskRPict1        = 56;
  156.     kTechDemoMaskRPict2        = 57;
  157.     kTechDemoMaskRPict3        = 58;
  158.     kTechDemoMaskRNone        = 60;
  159.     kTechDemoMaskRFirst        = 61;
  160.     kTechDemoMaskRLast        = 64;
  161.     { Error messages. ('STR ' resource IDs). }
  162.     kSys7Required            = 128;
  163.     kMemoryOut                = 129;
  164.     kGWorldErr                = 130;
  165.     kNotYetImplemented        = 131;
  166.     kMissingResource        = 132;
  167.     { The generic error alert ID. }
  168.     kAlertDialogID            = 129;
  169.     { Item numbers in the generic alert dialog. }
  170.     kAlertOKButton            = 1;
  171.     { Codes sent to the Slide routine to indicate which }
  172.     { way to slide the new picture in (from). }
  173.     kLeft =        1;
  174.     kRight =    2;
  175.     kTop =        3;
  176.     kBottom =    4;
  177.     { Codes sent to the Aperture routine to indicate which }
  178.     { way to do the effect. }
  179.     kIn =        1;
  180.     kOut =        2;
  181.     { Easy way to access colors in the global colors array. }
  182.     kWhite =    0;
  183.     kLtGray =    1;
  184.     kGray =        2;
  185.     kDkGray =    3;
  186.     kBlack =    4;
  187.  
  188. Var
  189.     colors:            array[0..4] of RGBColor;    { white, black, and 3 grays }
  190.     mainDlg,aDlg:    DialogPtr;
  191.     pict1Rect:        rect;
  192.     pict2Rect:        rect;
  193.     destRect:        rect;
  194.     savedPen:        PenState;
  195.     itemHit:        integer;
  196.     savedFore:        RGBColor;
  197.     savedBack:        RGBColor;
  198.     fadeSpeed:        integer;
  199.     myErr:            OSErr;
  200.     pict1GRect:        rect;
  201.     pict2GRect:        rect;
  202.     pict1GWorld:    GWorldPtr;
  203.     pict2GWorld:    GWorldPtr;
  204.     myEvent:        EventRecord;
  205.     aPict:            PicHandle;
  206.     myPictInfo:        PictInfo;
  207.     aDevice:        GDHandle;
  208.     dlgUpLeftCorner: point;
  209.     err:            OSErr;
  210.     tempRect:        rect;
  211.     mouseLoc:        point;
  212.  
  213. Function WinBitMap(w:    univ ptr): bitmap;
  214.  
  215.     begin
  216.     WinBitMap := GrafPtr(w)^.portBits;
  217.     end;
  218.  
  219. { FadeToImage takes the source image and does a smooth fade in
  220. { the destination window and rect from the image that is currently
  221. { there to the source image. This is done using CopyBits with
  222. { the "blend" transfer mode.}
  223. Procedure FadeToImage(srcImage: GWorldPtr; srcRect: Rect;
  224.                       destWin: WindowPtr; destRect: Rect; fadeSpeed: integer);
  225.  
  226. Var
  227.     savedPort:            CGrafPtr;
  228.     savedDevice:        GDHandle;
  229.     savedFore, 
  230.     savedBack:             RGBColor;
  231.     savedPen:            PenState;
  232.     grayColor:            RGBColor;
  233.     speed:                real;
  234.     lastColor:            integer;
  235.     
  236.     begin
  237.     { Make sure speed is within our limits and set it appropriately.
  238.     { We want to end up with a range of 1.2 to 3.2 from the original
  239.     { 0 to 20 range.}
  240.     if fadeSpeed < 1 then
  241.         speed := 1.2
  242.     else if fadeSpeed > 20 then
  243.         speed := 3.2
  244.     else
  245.         begin
  246.         speed := fadeSpeed;
  247.         speed := 1.2 + (speed/10);
  248.         end;
  249.     { Save the current port and device }
  250.     GetGWorld(savedPort, savedDevice);
  251.     { Set the port to the destination window and save its
  252.     { pen state and fore/background color values. }
  253.     SetGWorld(CGrafPtr(destWin), NIL);
  254.     GetPenState(savedPen);
  255.     GetForeColor(savedFore);
  256.     GetBackColor(savedBack);
  257.     { Make sure the port's fore and background colors are set
  258.     { correctly for CopyBits to work correctly.}
  259.     RGBForeColor(colors[kBlack]);
  260.     RGBBackColor(colors[kWhite]);
  261.     { Lock the pixels in the source image. This is required
  262.     { when copying from a GWorld. }
  263.     if not LockPixels(GetGWorldPixMap(srcImage)) then
  264.         ;
  265.     { Set the beginning blend weight. This will be multiplied by
  266.     { speed before being used the first time. }
  267.     grayColor.blue := $0F00;
  268.     grayColor.green := $0F00;
  269.     grayColor.red := $0F00;
  270.     lastColor := 0;
  271.     { Loop and copy the source image to the destination
  272.     { blending more and more of the source image in by using
  273.     { a lighter and lighter "blend weight" (set by the OpColor
  274.     { function).}
  275.     while (grayColor.blue <> $FFFF) do
  276.         begin
  277.         { Lighten the blend weight color. }
  278.         grayColor.blue := trunc(grayColor.blue * speed);
  279.         { Make sure the number didn't roll over. }
  280.         if (grayColor.blue < lastColor) then
  281.             grayColor.blue := $FFFF;
  282.         grayColor.red := grayColor.blue;
  283.         grayColor.green := grayColor.blue;
  284.         { Remember the number for next time. }
  285.         lastColor := grayColor.blue;
  286.         { Set the new blend weight. }
  287.         OpColor(grayColor);
  288.         { copy the image }
  289.         CopyBits(WinBitMap(srcImage), WinBitMap(destWin),
  290.             srcRect, destRect, blend, NIL);
  291.         end;
  292.     { Finally, just copy the source image to the destination
  293.     { window unchanged to make sure the transformation is
  294.     { complete. }
  295.     CopyBits(WinBitMap(srcImage), WinBitMap(destWin),
  296.             srcRect, destRect, srcCopy, NIL);
  297.     { Reset the blend weight to black.
  298.     { This is the "normal" weight.}
  299.     OpColor(colors[kBlack]);
  300.     { Unlock the pixels in the source image. }
  301.     UnlockPixels(GetGWorldPixMap(srcImage));
  302.     { Restore the destination window's properties. }
  303.     SetPenState(savedPen);
  304.     RGBForeColor(savedFore);
  305.     RGBBackColor(savedBack);
  306.     { Restore the current port and device. }
  307.     SetGWorld(savedPort, savedDevice);
  308.     end;
  309.  
  310. { FadeToBlack1 creates a black rectangle in an offscreen GWorld that
  311. { is the same size as the destination area. It then calls FadetoImage
  312. { to fade this into the destination thus fading it to black.
  313. }
  314. Procedure FadeToBlack1(destWin: WindowPtr; destRect: Rect; fadeSpeed: integer);
  315.  
  316. Var
  317.     savedPort:        CGrafPtr;
  318.     savedDevice:    GDHandle;
  319.     offscreenWorld:    GWorldPtr;
  320.     myErr:            OSErr;
  321.     
  322.     begin
  323.     { Save the current port/device. This should be used instead
  324.     { of GetPort. Though savedPort is defined as a CGrafPtr,
  325.     { the routine may return a GrafPtr or pointer to a GWorld
  326.     { instead (GWorldPtr).}
  327.     GetGWorld(savedPort,savedDevice);
  328.     {
  329.     { Create an offscreen GWorld with the same depth and size as the
  330.     { destination window/rectangle. Even though the rectangle is all the
  331.     { same shade, we make it the same size as the destination because
  332.     { CopyBits works much faster when it doesn't have to resize the
  333.     { image. The parameters are as follows:
  334.     {        &offscreenWorld        ptr to new graphics world
  335.     {        0                    bit depth same as graphics device of dest rect
  336.     {        destRect            bounds rectangle of my GWorld
  337.     {        NIL                handle to a color table record - NIL means
  338.     {                            use the default record for that depth
  339.     {        NIL                handle to a graphics device record - we aren't
  340.     {                            creating a new graphics device
  341.     {        0L                    no flags
  342.     }
  343.     myErr := NewGWorld(offscreenWorld, 0, destRect, NIL, NIL, 0);
  344.     { Make sure the GWorld was created }
  345.     if myErr <> NoErr then
  346.         begin
  347.         DoAlertStrID(kAlertDialogID, true, kGWorldErr);
  348.         ExitToShell;
  349.         end;
  350.     {
  351.     { Get the GWorld's pixel map handle and lock the pixels while we're
  352.     { drawing to the GWorld. We have to do this because a GWorld actually
  353.     { holds its pixel map in a handle rather than a pointer. LockPixels
  354.     { makes sure the pixel map doesn't move. You should lock a GWorld's
  355.     { pixels before drawing to or copying from the GWorld (and unlock
  356.     { them afterward).
  357.     }
  358.     if not LockPixels(GetGWorldPixMap(offscreenWorld)) then
  359.         ;
  360.     SetGWorld(offscreenWorld, NIL);    { Make the GWorld the current port. }
  361.     PaintRect(offscreenWorld^.portRect);    { Paint the offscreen GWorld all black. }
  362.     SetGWorld(savedPort, savedDevice);    { Restore the saved port/device. }
  363.     UnlockPixels(GetGWorldPixMap(offscreenWorld)); { Unlock the pixels of the GWorld.}
  364.     { Call FadeToImage to fade the black rectangle to the destination. }
  365.     FadeToImage(offscreenWorld, offscreenWorld^.portRect,
  366.             destWin, destRect, fadeSpeed);
  367.     DisposeGWorld(offscreenWorld);    { Now get rid of the black GWorld. }
  368.     end;
  369.  
  370. { FadeToBlack2 uses CopyBits and an offscreen graphics world to
  371. { fade an area (specified by destRect) in a window (specified
  372. { by destWin) to black. It does this by creating an offscreen
  373. { graphics world, painting the GWorld gray, then repeatedly
  374. { copying the gray rectangle to the destination area using the
  375. { subPin transfer method of CopyBits. This causes the destination
  376. { to grow darker and darker.
  377. }
  378. Procedure FadeToBlack2(destWin: WindowPtr; destRect: Rect; fadeSpeed: integer);
  379.  
  380. Var
  381.     savedPort:        CGrafPtr;
  382.     savedDevice:    GDHandle;
  383.     offscreenWorld:    GWorldPtr;
  384.     offscreenRect:    Rect;
  385.     myErr:            OSErr;
  386.     savedPen:        PenState;
  387.     savedFore:        RGBColor;
  388.     savedBack:        RGBColor;
  389.     repetitions:    longint;
  390.     grayColor:        RGBColor;
  391.     maxValue:        longint;
  392.     
  393.     begin
  394.     maxValue := $0FFFF;
  395.     { Save the current port/device. This should be used instead
  396.     { of GetPort. Though savedPort is defined as a CGrafPtr,
  397.     { the routine may return a GrafPtr or pointer to a GWorld
  398.     { instead (GWorldPtr).}
  399.     GetGWorld(savedPort,savedDevice);
  400.     { Set the current port to the destination window }
  401.     SetGWorld(CGrafPtr(destWin), NIL);
  402.     { Save the pen state and color info of the destination window }
  403.     GetPenState(savedPen);
  404.     GetForeColor(savedFore);
  405.     GetBackColor(savedBack);
  406.     { Make sure the foreground color of the destination window }
  407.     { is black and the background color is white. }
  408.     RGBForeColor(colors[kBlack]);
  409.     RGBBackColor(colors[kWhite]);
  410.     { Convert the destination rectangle into global coordinates }
  411.     offscreenRect := destRect;
  412.     LocalToGlobal(offscreenRect.topLeft);
  413.     LocalToGlobal(offscreenRect.botRight);
  414.     { Make the offscreen rectangle smaller. It doesn't matter since it's }
  415.     { all the same color and it'll use up less memory.}
  416.     offscreenRect.right := offscreenRect.left + 2;
  417.     offscreenRect.bottom := offscreenRect.top + 2;
  418.     { Create an offscreen GWorld with the same depth as the
  419.     { destination window/rectangle. The parameters are as follows:
  420.     {        &offscreenWorld        ptr to new graphics world
  421.     {        0                    bit depth same as graphics device of dest rect
  422.     {        &offscreenRect        bounds rectangle of my GWorld
  423.     {        NIL                handle to a color table record - NIL means
  424.     {                            use the default record for that depth
  425.     {        NIL                handle to a graphics device record - we aren't
  426.     {                            creating a new graphics device
  427.     {        0L                    no flags}
  428.     myErr := NewGWorld(offscreenWorld, 0, offscreenRect, NIL, NIL, 0);
  429.     { Make sure the GWorld was created }
  430.     if myErr <> NoErr then
  431.         begin
  432.         DoAlertStrID(kAlertDialogID, true, kGWorldErr);
  433.         ExitToShell;
  434.         end;
  435.     { Make the GWorld the current port }
  436.     SetGWorld(offscreenWorld, NIL);
  437.     { Get the GWorld's pixel map handle and lock the pixels while we're
  438.     { drawing in the GWorld. We have to do this because a GWorld actually
  439.     { holds its pixel map in a handle rather than a pointer. LockPixels
  440.     { makes sure the pixel map doesn't move. You should lock a GWorld's
  441.     { pixels before drawing to or copying from the GWorld (and unlock
  442.     { them afterward).}
  443.     if not LockPixels(GetGWorldPixMap(offscreenWorld)) then
  444.         ;
  445.     { The speed of the fade determines what shade of gray we'll paint
  446.     { the offscreen GWorld. fadeSpeed can range from 0 to 20 with 20
  447.     { being the fastest.}
  448.     if fadeSpeed <= 0 then
  449.         fadeSpeed := 1;    { make sure speed is not zero }
  450.     if fadeSpeed > 20 then
  451.         fadeSpeed := 20;    { make sure not over 20 }
  452.     grayColor.blue := (fadeSpeed * 625) + 8000;
  453.     grayColor.red := grayColor.blue;
  454.     grayColor.green := grayColor.blue;
  455.     RGBForeColor(grayColor);
  456.     repetitions := maxValue div grayColor.blue;
  457.     { Paint it all gray }
  458.     PaintRect(offscreenWorld^.portRect);
  459.     { Make the destination window the current port }
  460.     SetGWorld(CGrafPtr(destWin), NIL);
  461.     { Loop and use CopyBits to copy the gray rectangle into the
  462.     { destination window/rect using the subPin transfer method
  463.     { so that the picture gets darker and darker. }
  464.     while repetitions > 0 do
  465.         begin
  466.         CopyBits(WinBitMap(offscreenWorld), WinBitMap(destWin),
  467.                 offscreenWorld^.portRect, destRect, subPin, NIL);
  468.         dec(repetitions);
  469.         end;
  470.     { Make the GWorld the current port }
  471.     SetGWorld(offscreenWorld, NIL);
  472.     { Now we'll do a fast fade just to make sure everything went completely
  473.     { to black.}
  474.     grayColor.blue := 20500;
  475.     grayColor.red := grayColor.blue;
  476.     grayColor.green := grayColor.blue;
  477.     RGBForeColor(grayColor);
  478.     repetitions := maxValue div grayColor.blue + 1;
  479.     { Paint it all gray }
  480.     PaintRect(offscreenWorld^.portRect);
  481.     { Make the destination window the current port }
  482.     SetGWorld(CGrafPtr(destWin), NIL);
  483.     { Loop and use CopyBits to copy the gray rectangle into the
  484.     { destination window/rect using the subPin transfer method
  485.     { so that the picture gets darker and darker.}
  486.     while repetitions > 0 do
  487.         begin
  488.         CopyBits(WinBitMap(offscreenWorld), WinBitMap(destWin),
  489.                 offscreenWorld^.portRect, destRect, subPin, NIL);
  490.         dec(repetitions);
  491.         end;
  492.     { Unlock the pixels again. }
  493.     UnlockPixels(GetGWorldPixMap(offscreenWorld));
  494.     { Paint the destination rectangle all black. }
  495.     PaintRect(destRect);
  496.     { Restore the saved port/device }
  497.     SetGWorld(savedPort, savedDevice);
  498.     { Restore the pen state and color info of the destination window }
  499.     SetPenState(savedPen);
  500.     RGBForeColor(savedFore);
  501.     RGBBackColor(savedBack);
  502.     { Dispose of the GWorld }
  503.     DisposeGWorld(offscreenWorld);
  504.     end;
  505.  
  506. { FadeToBlack3 uses CopyBits and an offscreen graphics world to
  507. { fade an area (specified by destRect) in a window (specified
  508. { by destWin) to black. It does this by creating an offscreen
  509. { graphics world, and repeatedly copying darker and darker
  510. { shades of gray into the destination using the adMin transfer
  511. { method of CopyBits. This method compares the pixels in the
  512. { source (gray) and destination images and replaces the pixel
  513. { in the destination if the source is darker (closer to zero).
  514. { This has the effect of making the destination darker and
  515. { darker starting with the lighter colors and ending with the
  516. { darker colors and eventually blacking the destination out.
  517. }
  518. Procedure FadeToBlack3(destWin: WindowPtr; destRect: Rect; fadeSpeed: integer);
  519.  
  520. Var
  521.     savedPort:        CGrafPtr;
  522.     savedDevice:    GDHandle;
  523.     offscreenWorld:    GWorldPtr;
  524.     offscreenRect:    rect;
  525.     myErr:            OSerr;
  526.     savedFore:        RGBColor;
  527.     savedBack:        RGBColor;
  528.     grayColor:        RGBColor;
  529.     colorStep:        longint;
  530.     grayStep:        longint;
  531.     speed:            integer;
  532.     
  533.     begin
  534.     { Save the current port/device. This should be used instead
  535.     { of GetPort. Though savedPort is defined as a CGrafPtr,
  536.     { the routine may return a GrafPtr or pointer to a GWorld
  537.     { instead (GWorldPtr).}
  538.     GetGWorld(savedPort, savedDevice);
  539.     { Set the current port to the destination window.}
  540.     SetGWorld(CGrafPtr(destWin), NIL);
  541.     { Save the color info of the destination window.}
  542.     GetForeColor(savedFore);
  543.     GetBackColor(savedBack);
  544.     { Make sure the foreground color of the destination window
  545.     { is black and the background color is white.}
  546.     RGBForeColor(colors[kBlack]);
  547.     RGBBackColor(colors[kWhite]);
  548.     { Convert the destination rectangle into global coordinates.}
  549.     offscreenRect := destRect;
  550.     LocalToGlobal(offscreenRect.topleft);
  551.     LocalToGlobal(offscreenRect.botRight);
  552.     {LocalToGlobal(* (Point*) &(r.top));
  553.     LocalToGlobal(* (Point*) &(r.bottom));}
  554.     myErr := NewGWorld(offscreenWorld, 0, offscreenRect, NIL, NIL, 0);
  555.     { Make sure the GWorld was created }
  556.     if myErr <> NoErr then
  557.         begin
  558.         DoAlertStrID(kAlertDialogID, true, kGWorldErr);
  559.         ExitToShell;
  560.         end;
  561.     { Get the GWorld's pixel map handle and lock the pixels while we're
  562.     { drawing to the GWorld. We have to do this because a GWorld actually
  563.     { holds its pixel map in a handle rather than a pointer. LockPixels
  564.     { makes sure the pixel map doesn't move. You should lock a GWorld's
  565.     { pixels before drawing to or copying from the GWorld (and unlock
  566.     { them afterward).}
  567.     if not LockPixels(GetGWorldPixMap(offscreenWorld)) then
  568.         ;
  569.     { Determine the number to subtract from the gray shade every time we
  570.     { loop. This is determined by the fadeSpeed parameter.}
  571.     if fadeSpeed < 0 then
  572.         speed := 0
  573.     else if fadeSpeed > 20 then
  574.         speed := 20
  575.     else
  576.         speed := fadeSpeed;
  577.     colorStep := trunc($0FFFF / (21 - fadeSpeed)) div 2;
  578.     { Our gray color just starts out as white. }
  579.     grayColor := colors[kWhite];
  580.     grayStep := $0FFFF;
  581.     { Loop until the gray color is black. }
  582.     while (grayStep > 0) do
  583.         begin
  584.         { Make the GWorld the current port. }
  585.         SetGWorld(offscreenWorld, NIL);
  586.         { Subtract the color step value from the gray value and
  587.         { paint the offscreen GWorld.}
  588.         if (grayStep > colorStep) then
  589.             grayStep := grayStep - colorStep
  590.         else
  591.             grayStep := 0;
  592.         grayColor.blue := grayStep;
  593.         grayColor.green := grayColor.blue;
  594.         grayColor.red := grayColor.blue;
  595.         RGBForeColor(grayColor);
  596.         PaintRect(offscreenWorld^.portRect);
  597.         { Make the destination window the current port.}
  598.         SetGWorld(CGrafPtr(destWin), NIL);
  599.         { Use CopyBits with the adMin transfer mode to copy the
  600.         { gray rectangle to the destination window/area.}
  601.         CopyBits(WinBitMap(offscreenWorld), WinBitMap(destWin),
  602.             offscreenWorld^.portRect, destRect, adMin, NIL);
  603.         end;
  604.     { Set the current port to the destination window. }
  605.     SetGWorld(CGrafPtr(destWin), NIL);
  606.     { Restore the color info of the destination window. }
  607.     RGBForeColor(savedFore);
  608.     RGBBackColor(savedBack);
  609.     { Restore the saved port/device. }
  610.     SetGWorld(savedPort, savedDevice);
  611.     { Unlock the pixels of the GWorld and dispose of it. }
  612.     UnlockPixels(GetGWorldPixMap(offscreenWorld));
  613.     DisposeGWorld(offscreenWorld);
  614.     end;
  615.  
  616. { Pixelize makes a picture "blockier" in several steps.
  617. { It first copies the original picture from the destination
  618. { area, then repeatedly copies the original picture
  619. { into areas smaller than the size of the previous one,
  620. { using CopyBits to scale the picture back up into the
  621. { destination window at the original size.
  622. {
  623. { The srcWin/srcRect and destWin/destRect may be the same
  624. { window/area to pixelize, but not to depixelize.
  625. { When depixelizing, srcWin will usually be a GWorldPtr
  626. { containing an image the same size as the destination area.
  627. }
  628. Procedure Pixelize(srcWin: WindowPtr; srcRect: Rect;
  629.                    destWin: WindowPtr; destRect: Rect; speed: integer; pixelizing: boolean);
  630.  
  631. Var
  632.     srcImage:        GWorldPtr;
  633.     intermedImage:    GWorldPtr;
  634.     intermedRect:    Rect;
  635.     savedPort:        CGrafPtr;
  636.     savedDevice:    GDHandle;
  637.     myErr:            OSErr;
  638.     theSpeed:        real;
  639.     done:            boolean;
  640.     
  641.     begin
  642.     { Make sure speed is within our limits and set it appropriately.
  643.     { We want to end up with a range of 1.1 to 2.1 from the original
  644.     { 0 to 20 range.}
  645.     if (speed < 1) then
  646.         theSpeed := 1.1
  647.     else if (speed > 20) then
  648.         theSpeed := 2.1
  649.     else
  650.         begin
  651.         theSpeed := speed;
  652.         theSpeed := 1.1 + (theSpeed/20);
  653.         end;
  654.     { Save the original port and device. }
  655.     GetGWorld(savedPort, savedDevice);
  656.     { Create an offscreen GWorld with the same depth as the
  657.     { destination window/rectangle. The parameters are as follows:
  658.     {        &srcImage            ptr to new graphics world
  659.     {        0                    bit depth same as graphics device of dest rect
  660.     {        destRect            bounds rectangle of my GWorld
  661.     {        NIL                handle to a color table record - NIL means
  662.     {                            use the default record for that depth
  663.     {        NIL                handle to a graphics device record - we aren't
  664.     {                            creating a new graphics device
  665.     {        0L                    no flags }
  666.     myErr := NewGWorld(srcImage, 0, destRect, NIL, NIL, 0);
  667.     { Make sure the GWorld was created }
  668.     if myErr <> NoErr then
  669.         begin
  670.         DoAlertStrID(kAlertDialogID, true, kGWorldErr);
  671.         ExitToShell;
  672.         end;
  673.     { Also create an intermediate GWorld used in the scaling/copying. }
  674.     myErr := NewGWorld(intermedImage, 0, destRect, NIL, NIL, 0);
  675.     { Make sure the GWorld was created }
  676.     if myErr <> NoErr then
  677.         begin
  678.         DoAlertStrID(kAlertDialogID, true, kGWorldErr);
  679.         ExitToShell;
  680.         end;
  681.     { Copy the source image into the GWorld. }
  682.     SetGWorld(srcImage, NIL);
  683.     CopyBits(WinBitMap(srcWin), WinBitMap(srcImage),
  684.         srcRect, srcImage^.portRect, srcCopy, NIL);
  685.     { Lock the pixels of the source and intermediate GWorlds
  686.     { since we'll be copying from them. }
  687.     if not LockPixels(GetGWorldPixMap(srcImage)) then
  688.         ;
  689.     if not LockPixels(GetGWorldPixMap(intermedImage)) then
  690.         ;
  691.     { We need a beginning intermediate image size. }
  692.     if pixelizing then
  693.         intermedRect := intermedImage^.portRect
  694.     else
  695.         begin
  696.         intermedRect := intermedImage^.portRect;
  697.         intermedRect.bottom := intermedRect.bottom div 15;
  698.         intermedRect.right := intermedRect.right div 15;
  699.         end;
  700.     { Loop and copy the image into smaller GWorlds. }
  701.     done := false;
  702.     while not done do
  703.         begin
  704.         { Adjust the intermediate rectangle size and determine if
  705.         { this will be the last time through the loop. }
  706.         if pixelizing then
  707.             begin
  708.             intermedRect.bottom := trunc(intermedRect.bottom / theSpeed);
  709.             intermedRect.right := trunc(intermedRect.right / theSpeed);
  710.             if (intermedRect.bottom < (intermedImage^.portRect.bottom / 10)) then
  711.                 done := true;
  712.             end
  713.         else
  714.             begin
  715.             intermedRect.bottom := trunc(intermedRect.bottom * theSpeed);
  716.             intermedRect.right := trunc(intermedRect.right * theSpeed);
  717.             if ((intermedRect.bottom > intermedImage^.portRect.bottom) |
  718.                 (intermedRect.right > intermedImage^.portRect.right)) then
  719.                 begin
  720.                 intermedRect := intermedImage^.portRect;
  721.                 done := true;
  722.                 end;
  723.             end;
  724.         { Copy the original image into the intermediate GWorld. }
  725.         SetGWorld(CGrafPtr(intermedImage), NIL);
  726.         CopyBits(WinBitMap(srcImage), WinBitMap(intermedImage),
  727.             srcImage^.portRect, intermedRect, srcCopy, NIL);
  728.         { Copy the intermediate GWorld to the destination. }
  729.         SetGWorld(CGrafPtr(destWin), NIL);
  730.         CopyBits(WinBitMap(intermedImage), WinBitMap(destWin),
  731.             intermedRect, destRect, srcCopy, NIL);
  732.         end;
  733.     { Unlock everyone's pixels again. }
  734.     UnlockPixels(GetGWorldPixMap(srcImage));
  735.     UnlockPixels(GetGWorldPixMap(intermedImage));
  736.     { Restore the original port and device. }
  737.     SetGWorld(savedPort, savedDevice);
  738.     { Destroy the GWorld holding the original image and the
  739.     { intermediate GWorld. }
  740.     DisposeGWorld(srcImage);
  741.     DisposeGWorld(intermedImage);
  742.     end;
  743.  
  744. { FlickerAnimate animates a colored circle floating over
  745. { a picture at the mouse location. It draws directly to
  746. { the screen resulting in a circle that the background
  747. { occasionally "flickers" through. Drawing will occur in
  748. { the current port.
  749. }
  750. Procedure FlickerAnimate(srcPict: GWorldPtr; destRect: Rect);
  751.  
  752. Var
  753.     mouseLoc:    Point;
  754.     mouseRect:    Rect;
  755.     savedFore:    RGBColor;
  756.     savedBack:    RGBColor;
  757.     savedClip:    RgnHandle;
  758.     redColor:    RGBColor;
  759.     ignore:        longint;
  760.         
  761.     begin
  762.     { Make the color to draw the circle with. }
  763.     redColor.blue := 0;
  764.     redColor.green := 0;
  765.     redColor.red := $0FFFF;
  766.     { Save fore and background colors and make them
  767.     { fore-black and back-white. }
  768.     GetForeColor(savedFore); 
  769.     GetBackColor(savedBack);
  770.     RGBForeColor(colors[kBlack]); 
  771.     RGBBackColor(colors[kWhite]);
  772.     { Save the clipping region. }
  773.     savedClip := NewRgn;
  774.     GetClip(savedClip);
  775.     { Set the clipping region to just cover the picture. }
  776.     ClipRect(destRect);
  777.     { Lock the pixel map of the src GWorld while copying from it. }
  778.     if not LockPixels(GetGWorldPixMap(srcPict)) then
  779.         ;
  780.     { Loop and draw the picture and circle repeatedly. }
  781.     repeat
  782.         { Get a mouse location. }
  783.         GetMouse(mouseLoc);
  784.         { Make a square around the mouse location to draw
  785.         { the circle in. }
  786.         mouseRect.left := mouseLoc.h;
  787.         mouseRect.right := mouseLoc.h;
  788.         mouseRect.top := mouseLoc.v;
  789.         mouseRect.bottom := mouseLoc.v;
  790.         InsetRect(mouseRect, -20, -20);
  791.         { Copy the picture to the window. }
  792.         CopyBits(WinBitMap(srcPict), WinBitMap(FrontWindow),
  793.                 srcPict^.portRect, destRect, srcCopy, NIL);
  794.         { Draw the circle at the mouse location. }
  795.         RGBForeColor(redColor);
  796.         PaintOval(mouseRect);
  797.         RGBForeColor(colors[kBlack]);
  798.         { Delay for a fraction of a second here. If we
  799.         { don't, the flickering is really, really bad. }
  800.         Delay(2, ignore);
  801.     until not PtInRect(mouseLoc, destRect);
  802.     { Draw the picture one more time to make sure the
  803.     { circle is erased. }
  804.     CopyBits(WinBitMap(srcPict), WinBitMap(FrontWindow()),
  805.             srcPict^.portRect, destRect, srcCopy, NIL);
  806.     { Unlock the GWorld's pixel map. }
  807.     UnlockPixels(GetGWorldPixMap(srcPict));
  808.     { Restore the clipping region. }
  809.     SetClip(savedClip);
  810.     { Restore the saved fore and background colors. }
  811.     RGBForeColor(savedFore);
  812.     RGBBackColor(savedBack);
  813.     end;
  814.  
  815. { SmoothAnimate animates a colored circle floating over
  816. { a picture at the mouse location. It draws to a GWorld
  817. { then copies the GWorld to the screen. This results in
  818. { flicker-free animation where the background never
  819. { shows through the floating circle.
  820. }
  821. Procedure SmoothAnimate(srcPict: GWorldPtr; destRect: rect);
  822.  
  823. Var
  824.     mouseLoc:        Point;
  825.     mouseRect:        Rect;
  826.     savedFore:        RGBColor;
  827.     savedBack:        RGBColor;
  828.     srcPixMap:        PixMapHandle;
  829.     midPixMap:        PixMapHandle;
  830.     middleMan:        GWorldPtr;
  831.     thisWindow:        CGrafPtr;
  832.     thisDevice:        GDHandle;
  833.     purpleColor:    RGBColor;
  834.     myErr:            OSErr;
  835.     
  836.     begin
  837.     { Save the current window and device (this is the window
  838.     { we're drawing into.) }
  839.     GetGWorld(thisWindow, thisDevice);
  840.     { Make the color to draw the circle with. }
  841.     purpleColor.blue := $0FFFF;
  842.     purpleColor.red := $0FFFF;
  843.     purpleColor.green := 0;
  844.     { Save fore and background colors and make them
  845.     { fore-black and back-white. }
  846.     GetForeColor(savedFore); 
  847.     GetBackColor(savedBack);
  848.     RGBForeColor(colors[kBlack]); 
  849.     RGBBackColor(colors[kWhite]);
  850.     myErr := NewGWorld(middleMan, 0, destRect, NIL, NIL, 0);
  851.     { Make sure the GWorld was created }
  852.     if (myErr <> NoErr) | (middleMan = NIL) then
  853.         begin
  854.         DoAlertStrID(kAlertDialogID, true, kGWorldErr);
  855.         ExitToShell;
  856.         end;
  857.     { Lock the pixel map of the src GWorld and the middleMan
  858.     { GWorld while copying from them. }
  859.     srcPixMap := GetGWorldPixMap(srcPict);
  860.     if not LockPixels(srcPixMap) then;
  861.     midPixMap := GetGWorldPixMap(middleMan);
  862.     if not LockPixels(midPixMap) then;
  863.     { Loop and draw the pict and the circle repeatedly. }
  864.     repeat
  865.         { Get a mouse location and translate into coordinates
  866.         { local to the middleMan GWorld. }
  867.         GetMouse(mouseLoc);
  868.         mouseLoc.h := mouseLoc.h - destRect.left;
  869.         mouseLoc.v := mouseLoc.v - destRect.top;
  870.         { Make a square around the mouse location to draw
  871.         { the circle in. }
  872.         mouseRect.left := mouseLoc.h;
  873.         mouseRect.right := mouseLoc.h;
  874.         mouseRect.top := mouseLoc.v;
  875.         mouseRect.bottom := mouseLoc.v;
  876.         InsetRect(mouseRect, -20, -20); 
  877.         { Set the current port to middleMan. }
  878.         SetGWorld(CGrafPtr(middleMan), NIL);
  879.         { Copy the picture to the middleMan GWorld. }
  880.         CopyBits(WinBitMap(srcPict), WinBitMap(middleMan),
  881.                 srcPict^.portRect, middleMan^.portRect, srcCopy, NIL);
  882.         { Draw the circle at the mouse location. }
  883.         RGBForeColor(purpleColor);
  884.         PaintOval(mouseRect);
  885.         RGBForeColor(colors[kBlack]);
  886.         { Reset the current port to the destination window. }
  887.         SetGWorld(thisWindow, thisDevice);
  888.         { Now copy the middleMan image to the destination
  889.         { window on screen. }
  890.         CopyBits(WinBitMap(middleMan), WinBitMap(thisWindow),
  891.                 middleMan^.portRect, destRect, srcCopy, NIL);
  892.     until not PtInRect(mouseLoc, middleMan^.portRect);
  893.     { Draw the picture one more time to make sure the
  894.     { circle is erased. }
  895.     CopyBits(WinBitMap(srcPict), WinBitMap(FrontWindow),
  896.             srcPict^.portRect, destRect, srcCopy, NIL);
  897.     { Unlock the GWorld's and middleMan's pixel maps. }
  898.     UnlockPixels(srcPixMap);
  899.     UnlockPixels(midPixMap);
  900.     { Dispose of the middleMan GWorld. }
  901.     DisposeGWorld(middleMan);
  902.     { Restore the saved fore and background colors. }
  903.     RGBForeColor(savedFore);
  904.     RGBBackColor(savedBack);
  905.     end;
  906.  
  907. { Blur blurs the destination picture by varying the destination image
  908. { in an offscreen GWorld slightly and blending the varied images back
  909. { into the original destination image.
  910. }
  911. Procedure Blur(destWin: WindowPtr; destRect: rect);
  912.  
  913. Var
  914.     savedPort:        CGrafPtr;
  915.     savedDevice:    GDHandle;
  916.     offscreenWorld:    GWorldPtr;
  917.     copyRect:        Rect;
  918.     savedFore:        RGBColor;
  919.     savedBack:        RGBColor;
  920.     grayColor:        RGBColor;
  921.     myErr:            OSErr;
  922.     x:                integer;
  923.     savedClip:        RgnHandle;
  924.     
  925.     begin
  926.     { Save the current device and port. }
  927.     GetGWorld(savedPort, savedDevice);
  928.     { Create a GWorld the same size as the destination image
  929.     { with the same depth as the destination window/rectangle.
  930.     { The parameters are as follows:
  931.     {        &offscreenWorld        ptr to new graphics world
  932.     {        0                    bit depth same as graphics device of dest rect
  933.     {        destRect            bounds rectangle of my GWorld
  934.     {        NIL                handle to a color table record - NIL means
  935.     {                            use the default record for that depth
  936.     {        NIL                handle to a graphics device record - we aren't
  937.     {                            creating a new graphics device
  938.     {        0                    no flags }
  939.     myErr := NewGWorld(offscreenWorld, 0, destRect, NIL, NIL, 0);
  940.     { Make sure the GWorld was created }
  941.     if myErr <> NoErr then
  942.         begin
  943.         DoAlertStrID(kAlertDialogID, true, kGWorldErr);
  944.         ExitToShell;
  945.         end;
  946.     { Make the GWorld the current port. }
  947.     SetGWorld(CGrafPtr(offscreenWorld), NIL);
  948.     { Copy the destination image into the GWorld. }
  949.     CopyBits(WinBitMap(destWin), WinBitMap(offscreenWorld),
  950.         destRect, offscreenWorld^.portRect, srcCopy, NIL);
  951.     { Make the destination window the current port. }
  952.     SetGWorld(CGrafPtr(destWin), NIL);
  953.     { Save the destination window's fore/background colors. }
  954.     GetBackColor(savedBack);
  955.     GetForeColor(savedFore);
  956.     { Make sure the destination window's fore/background colors
  957.     { are black/white. }
  958.     RGBForeColor(colors[kBlack]);
  959.     RGBBackColor(colors[kWhite]);
  960.     { Save the destination window's clip region and set it to
  961.     { the destination rectangle. }
  962.     savedClip := NewRgn;
  963.     GetClip(savedClip);
  964.     ClipRect(destRect);
  965.      { Set the OpColor for blending. }
  966.     grayColor.red := $4000;
  967.     grayColor.green := $4000;
  968.     grayColor.blue := $4000;
  969.     OpColor(grayColor);
  970.     { Lock the GWorld's pixels while we copy from it. }
  971.     if not LockPixels(GetGWorldPixMap(offscreenWorld)) then;
  972.     { Blend the GWorld image back into the destination image in
  973.     { a circular pattern. }
  974.     for x := 1 to 8 do
  975.         begin
  976.         copyRect := destRect;
  977.         case x of
  978.             1:    OffsetRect(copyRect, -2, 0);
  979.             2:    OffsetRect(copyRect, -1, -1);
  980.             3:    OffsetRect(copyRect, 0, -2);
  981.             4:    OffsetRect(copyRect, 1, -1);
  982.             5:    OffsetRect(copyRect, 2, 0);
  983.             6:    OffsetRect(copyRect, 1, 1);
  984.             7:    OffsetRect(copyRect, 0, 2);
  985.             8:    OffsetRect(copyRect, -1, 1);
  986.         {CASE}    end;
  987.         CopyBits(WinBitMap(offscreenWorld), WinBitMap(destWin),
  988.             offscreenWorld^.portRect, copyRect, blend, NIL);
  989.         end;
  990.     { Unlock the GWorld's pixels. }
  991.     UnlockPixels(GetGWorldPixMap(offscreenWorld));
  992.     { Reset OpColor to black. }
  993.     OpColor(colors[kBlack]);
  994.     { Get rid of the GWorld. }
  995.     DisposeGWorld(offscreenWorld);
  996.     { Restore the destination window's fore/background colors.}
  997.     RGBForeColor(savedFore);
  998.     RGBBackColor(savedBack);
  999.      { Restore the destination window's clipping region. }
  1000.     SetClip(savedClip);
  1001.     DisposeRgn(savedClip);
  1002.     { Restore the saved port and device. }
  1003.     SetGWorld(savedPort, savedDevice);
  1004.     end;
  1005.  
  1006. { FlipHorizontal copies the image in the window and rectangle
  1007. { specified and draws it back out reversed horizontally.
  1008. }
  1009. Procedure FlipHorizontal(destWin: WindowPtr; destRect: Rect);
  1010.  
  1011. Var
  1012.     savedPort:        CGrafPtr;
  1013.     savedDevice:    GDHandle;
  1014.     offscreenWorld:    GWorldPtr;
  1015.     savedFore:        RGBColor;
  1016.     savedBack:        RGBColor;
  1017.     myErr:            OSErr;
  1018.     x:                integer;
  1019.     copyFrom:        Rect;
  1020.     copyTo:            Rect;
  1021.     
  1022.     begin
  1023.     { Save the current device and port. }
  1024.     GetGWorld(savedPort, savedDevice);
  1025.     myErr := NewGWorld(offscreenWorld, 0, destRect, NIL, NIL, 0);
  1026.     { Make sure the GWorld was created }
  1027.     if myErr <> NoErr then
  1028.         begin
  1029.         DoAlertStrID(kAlertDialogID, true, kGWorldErr);
  1030.         ExitToShell;
  1031.         end;
  1032.     { Make the GWorld the current port. }
  1033.     SetGWorld(CGrafPtr(offscreenWorld), NIL);
  1034.     { Set up the copy from and to rectangles. }
  1035.     copyFrom := destRect;
  1036.     copyFrom.right := copyFrom.left + 1;
  1037.     copyTo := offscreenWorld^.portRect;
  1038.     copyTo.left := copyTo.right - 1;
  1039.     { Copy the destination image into the GWorld column by column
  1040.     { reversing it as we go. }
  1041.     for x := 1 to (destWin^.portRect.right - destWin^.portRect.left) do
  1042.         begin
  1043.         CopyBits(WinBitMap(destWin), WinBitMap(offscreenWorld),
  1044.             copyFrom, copyTo, srcCopy, NIL);
  1045.         OffsetRect(copyFrom, 1, 0);
  1046.         OffsetRect(copyTo, -1, 0);
  1047.         end;
  1048.     { Make the destination window the current port. }
  1049.     SetGWorld(CGrafPtr(destWin), NIL);
  1050.     { Save the destination window's fore/background colors. }
  1051.     GetBackColor(savedBack);
  1052.     GetForeColor(savedFore);
  1053.     { Make sure the destination window's fore/background colors
  1054.     { are black/white. }
  1055.     RGBForeColor(colors[kBlack]);
  1056.     RGBBackColor(colors[kWhite]);
  1057.     { Lock the GWorld's pixels while we copy from it. }
  1058.     if not LockPixels(GetGWorldPixMap(offscreenWorld)) then;
  1059.     { Now copy the reversed image back to the destination window. }
  1060.     CopyBits(WinBitMap(offscreenWorld), WinBitMap(destWin),
  1061.         offscreenWorld^.portRect, destRect, srcCopy, NIL);
  1062.     { Unlock the GWorld's pixels now. }
  1063.     UnlockPixels(GetGWorldPixMap(offscreenWorld));
  1064.     { Get rid of the GWorld. }
  1065.     DisposeGWorld(offscreenWorld);
  1066.     { Restore the destination window's fore/background colors. }
  1067.     RGBForeColor(savedFore);
  1068.     RGBBackColor(savedBack);
  1069.     { Restore the saved port and device. }
  1070.     SetGWorld(savedPort, savedDevice);
  1071.     end;
  1072.  
  1073. { FlipVertical copies the image in the window and rectangle
  1074. { specified and draws it back out reversed vertically.
  1075. }
  1076. Procedure FlipVertical(destWin: WindowPtr; destRect: rect);
  1077.  
  1078. Var
  1079.     savedPort:        CGrafPtr;
  1080.     savedDevice:    GDHandle;
  1081.     offscreenWorld:    GWorldPtr;
  1082.     savedFore:        RGBColor;
  1083.     savedBack:        RGBColor;
  1084.     myErr:            OSErr;
  1085.     x:                integer;
  1086.     copyFrom:        rect;
  1087.     copyTo:            rect;
  1088.     
  1089.     begin
  1090.     { Save the current device and port. }
  1091.     GetGWorld(savedPort, savedDevice);
  1092.     myErr := NewGWorld(offscreenWorld, 0, destRect, NIL, NIL, 0);
  1093.     { Make sure the GWorld was created }
  1094.     if myErr <> NoErr then
  1095.         begin
  1096.         DoAlertStrID(kAlertDialogID, true, kGWorldErr);
  1097.         ExitToShell;
  1098.         end;
  1099.     { Make the GWorld the current port. }
  1100.     SetGWorld(CGrafPtr(offscreenWorld), NIL);
  1101.     { Set up the copy from and to rectangles. }
  1102.     copyFrom := destRect;
  1103.     copyFrom.bottom := copyFrom.top + 1;
  1104.     copyTo := offscreenWorld^.portRect;
  1105.     copyTo.top := copyTo.bottom - 1;
  1106.     { Copy the destination image into the GWorld row by row
  1107.     { reversing it as we go. }
  1108.     for x := 1 to (destWin^.portRect.bottom - destWin^.portRect.top) do
  1109.         begin
  1110.         CopyBits(WinBitMap(destWin), WinBitMap(offscreenWorld),
  1111.             copyFrom, copyTo, srcCopy, NIL);
  1112.         OffsetRect(copyFrom, 0, 1);
  1113.         OffsetRect(copyTo, 0, -1);
  1114.         end;
  1115.     { Make the destination window the current port. }
  1116.     SetGWorld(CGrafPtr(destWin), NIL);
  1117.     { Save the destination window's fore/background colors. }
  1118.     GetBackColor(savedBack);
  1119.     GetForeColor(savedFore);
  1120.     { Make sure the destination window's fore/background colors
  1121.     { are black/white. }
  1122.     RGBForeColor(colors[kBlack]);
  1123.     RGBBackColor(colors[kWhite]);
  1124.     { Lock the GWorld's pixels while we copy from it. }
  1125.     if not LockPixels(GetGWorldPixMap(offscreenWorld)) then;
  1126.     { Now copy the reversed image back to the destination window. }
  1127.     CopyBits(WinBitMap(offscreenWorld), WinBitMap(destWin),
  1128.         offscreenWorld^.portRect, destRect, srcCopy, NIL);
  1129.     { Unlock the GWorld's pixels now. }
  1130.     UnlockPixels(GetGWorldPixMap(offscreenWorld));
  1131.     { Get rid of the GWorld. }
  1132.     DisposeGWorld(offscreenWorld);
  1133.     { Restore the destination window's fore/background colors. }
  1134.     RGBForeColor(savedFore);
  1135.     RGBBackColor(savedBack);
  1136.     { Restore the saved port and device. }
  1137.     SetGWorld(savedPort, savedDevice);
  1138.     end;
  1139.  
  1140. { Slide slides the source image onto the destination from the
  1141. { direction specified in whichWay.
  1142. }
  1143. Procedure Slide(srcWin: WindowPtr; srcRect: Rect;
  1144.                 destWin: WindowPtr; destRect: Rect; speed,whichWay: integer);
  1145.  
  1146. Var
  1147.     savedFore:        RGBColor;
  1148.     savedBack:        RGBColor;
  1149.     savedPort:        CGrafPtr;
  1150.     savedDevice:    GDHandle;
  1151.     x,speedToUse:    integer;
  1152.     pixelsPerLoop:    integer;
  1153.     pixelsToMove:    integer;
  1154.     savedClip:        RgnHandle;
  1155.     drawDest:        Rect;
  1156.     hDelta, vDelta:    integer;
  1157.     iterations:        integer;
  1158.     delayPerLoop:    longint;
  1159.     ignore:            longint;
  1160.     
  1161.     begin
  1162.     { Make sure the speed is within acceptable range. Normally
  1163.     { zero is the slowest speed, but we're changing that to 1
  1164.     { for this routine. }
  1165.     if (speed <= 0) then
  1166.         speedToUse := 1
  1167.     else if (speed > 20) then
  1168.         speedToUse := 20
  1169.     else 
  1170.         speedToUse := speed;
  1171.     { Determine how much to delay each loop based on the size
  1172.     { of the destination. }
  1173.     x := (destRect.right - destRect.left);
  1174.     if (x < 200) then
  1175.         delayPerLoop := 5
  1176.     else if (x < 400) then
  1177.         delayPerLoop := 4
  1178.     else if (x < 600) then
  1179.         delayPerLoop := 3
  1180.     else if (x < 800) then
  1181.         delayPerLoop := 2
  1182.     else if (x < 1000) then
  1183.         delayPerLoop := 1
  1184.     else 
  1185.         delayPerLoop := 0;
  1186.     { If the destination is not the same size as the source,
  1187.     { cut the delay in half to compensate for sizing the picture.
  1188.     { I could, of course just copy the source into a GWorld that
  1189.     { is the same size as the destination and the sizing would only
  1190.     { take place once, but that would also require much more
  1191.     { memory than the way I'm doing it now (just copying/sizing
  1192.     { each time). }
  1193.     if ((destRect.right - destRect.left) <> (srcRect.right - srcRect.left)) |
  1194.         ((destRect.bottom - destRect.top) <> (srcRect.bottom - srcRect.top)) then
  1195.         delayPerLoop := delayPerLoop div 2;
  1196.     { Determine how many pixels the source will have to move to
  1197.     { completely cover the destination. This depends on the
  1198.     { direction that we're moving. }
  1199.     if (whichWay = kLeft) | (whichWay = kRight) then
  1200.         pixelsToMove := destRect.right - destRect.left
  1201.     else
  1202.         pixelsToMove := destRect.bottom - destRect.top;
  1203.     { Determine how many pixels to move the source over onto the
  1204.     { destination each time through the loop based on the speed
  1205.     { parameter. }
  1206.     pixelsPerLoop := speedToUse * 2;
  1207.     { Save the current port and set it to the destination window. }
  1208.     GetGWorld(savedPort, savedDevice);
  1209.     SetGWorld(CGrafPtr(destWin), NIL);
  1210.     { Save the dest window's colors and set them to black/white. }
  1211.     GetForeColor(savedFore);  
  1212.     RGBForeColor(colors[kBlack]);
  1213.     GetBackColor(savedBack);  
  1214.     RGBBackColor(colors[kWhite]);
  1215.     { Save the destination window's clipping region and clip
  1216.     { to the destination rectangle. }
  1217.     savedClip := NewRgn;
  1218.     GetClip(savedClip);
  1219.     ClipRect(destRect);
  1220.     { Determine where the drawing destination rectangle should
  1221.     { initially be. At the same time, set the horizontal and
  1222.     { vertical deltas for moving the rectangle. }
  1223.     drawDest := destRect;
  1224.     hDelta := 0;
  1225.     vDelta := 0;
  1226.     case whichWay of
  1227.         kLeft:    begin
  1228.                 OffsetRect(drawDest, -pixelsToMove, 0);
  1229.                 hDelta := pixelsPerLoop;
  1230.                 end;
  1231.         kRight:    begin
  1232.                 OffsetRect(drawDest, pixelsToMove, 0);
  1233.                 hDelta := -pixelsPerLoop;
  1234.                 end;
  1235.         kTop:    begin
  1236.                 OffsetRect(drawDest, 0, -pixelsToMove);
  1237.                 vDelta := pixelsPerLoop;
  1238.                 end;
  1239.         kBottom:begin
  1240.                 OffsetRect(drawDest, 0, pixelsToMove);
  1241.                 vDelta := -pixelsPerLoop;
  1242.                 end;
  1243.         {CASE}    end;
  1244.     { Loop how many times? }
  1245.     iterations := pixelsToMove div pixelsPerLoop;
  1246.     { Loop and move the source onto the image. }
  1247.     for x := 1 to iterations do
  1248.         begin
  1249.         { Move the drawing destination rectangle. }
  1250.         OffsetRect(drawDest, hDelta, vDelta);
  1251.         { Now copy the source image into the drawing
  1252.         { destination rectangle we just moved. }
  1253.         CopyBits(WinBitMap(srcWin), WinBitMap(destWin),
  1254.             srcRect, drawDest, srcCopy, NIL);
  1255.         { Delay. }
  1256.         if delayPerLoop > 0 then
  1257.             Delay(delayPerLoop, ignore);
  1258.         end;
  1259.     { Copy the image directly into the destination to make
  1260.     { sure the move is complete. }
  1261.     CopyBits(WinBitMap(srcWin), WinBitMap(destWin),
  1262.             srcRect, destRect, srcCopy, NIL);
  1263.     { Restore the clipping region. }
  1264.     SetClip(savedClip);
  1265.     DisposeRgn(savedClip);
  1266.     { Restore the dest window's colors. }
  1267.     RGBForeColor(savedFore);
  1268.     RGBBackColor(savedBack);
  1269.     { Restore the saved port. }
  1270.     SetGWorld(savedPort, savedDevice);
  1271.     end;
  1272.  
  1273. { Aperture introduces the source image onto the destination either
  1274. { from the inside of a growing circle, or the outside of a shrinking
  1275. { circle. We use CopyMask along with a circle drawn in a GWorld to
  1276. { accomplish this.
  1277. }
  1278. Procedure Aperture(srcWin: WindowPtr; srcRect: Rect;
  1279.                    destWin: WindowPtr; destRect: Rect; speed,inOrOut: integer);
  1280.  
  1281. Var
  1282.     speedToUse:        integer;
  1283.     savedPort:        CGrafPtr;
  1284.     savedDevice:    GDHandle;
  1285.     savedFore:        RGBColor;
  1286.     savedBack:        RGBColor;
  1287.     savedClip:        RgnHandle;
  1288.     maskWorld:        GWorldPtr;
  1289.     maskRect:        Rect;
  1290.     sizeDelta:        integer;
  1291.     destSize:        integer;
  1292.     x,steps:        integer;
  1293.     
  1294.     begin
  1295.     { Save the current port/device. }
  1296.     GetGWorld(savedPort, savedDevice);
  1297.     { Create a GWorld for the mask image the same size as the
  1298.     { destination rectangle. }
  1299.     SetGWorld(CGrafPtr(srcWin), NIL);
  1300.     if NewGWorld(maskWorld, 0, srcRect, NIL, NIL, 0) <> noErr then
  1301.         begin
  1302.         DoAlertStrID(kAlertDialogID, true, kGWorldErr);
  1303.         ExitToShell;
  1304.         end
  1305.     else
  1306.         if not LockPixels(GetGWorldPixMap(maskWorld)) then;
  1307.     { Set the current port to the destination window. }
  1308.     SetGWorld(CGrafPtr(destWin), NIL);
  1309.     { Save the port's colors and set them to black/white. }
  1310.     GetForeColor(savedFore);  
  1311.     RGBForeColor(colors[kBlack]);
  1312.     GetBackColor(savedBack);  
  1313.     RGBBackColor(colors[kWhite]);
  1314.     { Save the port's clip region and clip to the destination rect. }
  1315.     savedClip := NewRgn;
  1316.     GetClip(savedClip);
  1317.     ClipRect(destRect);
  1318.     { Make sure the speed is within the correct range. }
  1319.     if speed <= 0 then
  1320.          speedToUse := 1
  1321.     else if speed > 20 then
  1322.         speedToUse := 20
  1323.     else 
  1324.         speedToUse := speed;
  1325.     { Determine if the destination rectangle is wider than it
  1326.     { is tall or the other way around and save the bigger number. }
  1327.     if (destRect.right - destRect.left) > (destRect.bottom - destRect.top) then
  1328.         destSize := destRect.right - destRect.left
  1329.     else
  1330.         destSize := destRect.bottom - destRect.top;
  1331.     { Make the rectangle that the circle will start in and create
  1332.     { a delta value to determine if the circle gets bigger or
  1333.     { smaller and by how much each time through the loop.
  1334.     { Make sure it's square. }
  1335.     maskRect := maskWorld^.portRect;
  1336.     if maskRect.bottom - maskRect.top > maskRect.right - maskRect.left then
  1337.         begin
  1338.         x := maskRect.bottom - maskRect.top;
  1339.         InsetRect(maskRect, -(x - (maskRect.right - maskRect.left)) div 2, 0);
  1340.         end
  1341.     else
  1342.         begin
  1343.         x := maskRect.right - maskRect.left;
  1344.         InsetRect(maskRect, 0, -(x - (maskRect.bottom - maskRect.top)) div 2);
  1345.         end;
  1346.     if inOrOut = kIn then
  1347.         begin
  1348.         sizeDelta := destSize div ((21-speedToUse) * 5) + 1;
  1349.         InsetRect(maskRect, -trunc(destSize*0.1), -trunc(destSize*0.1));
  1350.         steps := trunc((destSize*1.2) / (sizeDelta*2));
  1351.         end
  1352.     else
  1353.         begin
  1354.         sizeDelta := -(destSize div ((21-speedToUse) * 5) + 1);
  1355.         InsetRect(maskRect, trunc((destSize/2)*0.9), trunc((destSize/2)*0.9));
  1356.         steps := -trunc((destSize*1.2)/(sizeDelta*2));
  1357.         end;
  1358.     { Loop and copy the source image through the mask to the
  1359.     { destination making the mask circle bigger or smaller each
  1360.     { time. }
  1361.     for x := 1 to steps do
  1362.         begin
  1363.         { Draw the circle in the mask GWorld. }
  1364.         SetGWorld(CGrafPtr(maskWorld), NIL);
  1365.         EraseRect(maskWorld^.portRect);
  1366.         PaintArc(maskRect, 0, 360);
  1367.         { If we're going inward, invert the mask GWorld. }
  1368.         if inOrOut = kIn then
  1369.             InvertRect(maskWorld^.portRect);
  1370.         { Copy the source through the mask to the dest. }
  1371.         SetGWorld(CGrafPtr(destWin), NIL);
  1372.         CopyMask(WinBitMap(srcWin), WinBitMap(maskWorld),
  1373.             WinBitMap(destWin), srcRect, maskWorld^.portRect, destRect);
  1374.         { Change the size of the circle. }
  1375.         InsetRect(maskRect, sizeDelta, sizeDelta);
  1376.         end;
  1377.     { Copy the source image directly to the destination to make
  1378.     { sure it ends correctly.}
  1379.     CopyBits(WinBitMap(srcWin), WinBitMap(destWin),
  1380.         srcRect, destRect, srcCopy, NIL);
  1381.     { Restore the port's colors and clip region. }
  1382.     SetClip(savedClip);
  1383.     RGBForeColor(savedFore);
  1384.     RGBBackColor(savedBack);
  1385.     { Restore the saved port. }
  1386.     SetGWorld(savedPort, savedDevice);
  1387.     { Dispose of the GWorld we used for the mask. }
  1388.     UnlockPixels(GetGWorldPixMap(maskWorld));
  1389.     DisposeGWorld(maskWorld);
  1390.     end;
  1391.  
  1392. { DrawMaskRegion draws the contents of each of the three mask regions.
  1393. { The drawing takes place in the rectangle of the item sent as the
  1394. { drawWhere parameter. The whichMask parameter determines what is
  1395. { drawn. When creating the actual mask region to use in the CopyBits
  1396. { operation, we have to make sure and draw the region in the coordinates
  1397. { of the destination image.
  1398. }
  1399. Procedure DrawMaskRegion(win: WindowPtr; drawWhere,whichMask: integer);
  1400.  
  1401. Var
  1402.     tempRect:    rect;
  1403.     tempRect2:    rect;
  1404.     x:            integer;
  1405.     vMid,hMid:    integer;
  1406.     
  1407.     begin
  1408.     GetItemRect(win, drawWhere, tempRect);
  1409.     case whichMask of
  1410.         1:        { Star }
  1411.                 begin
  1412.                 vMid := tempRect.top + (tempRect.bottom - tempRect.top) div 2;
  1413.                 hMid := tempRect.left + (tempRect.right - tempRect.left) div 2;
  1414.                 MoveTo(hMid, tempRect.top);
  1415.                 LineTo(hMid+4, vMid-4);
  1416.                 LineTo(tempRect.right, vMid);
  1417.                 LineTo(hMid+4, vMid+4);
  1418.                 LineTo(hMid, tempRect.bottom);
  1419.                 LineTo(hMid-4, vMid+4);
  1420.                 LineTo(tempRect.left, vMid);
  1421.                 LineTo(hMid-4, vMid-4);
  1422.                 LineTo(hMid, tempRect.top);
  1423.                 end;
  1424.         2:        { Square in middle }
  1425.                 begin
  1426.                 InsetRect(tempRect, 10, 10);
  1427.                 FrameRect(tempRect);
  1428.                 end;
  1429.         3:        { Concentric Squares }
  1430.                 begin
  1431.                 tempRect2 := tempRect;
  1432.                 while (tempRect2.right - tempRect2.left) > 2 do
  1433.                     begin
  1434.                     FrameRect(tempRect2);
  1435.                     InsetRect(tempRect2, 2, 2);
  1436.                     end;
  1437.                 end;
  1438.         {CASE}    end;
  1439.     end;
  1440.  
  1441. { FullScreenDemo fades the whole screen to black, then to picture one
  1442. { then to picture two and finally to the original screen (which is
  1443. { saved in a GWorld).
  1444. }
  1445. Procedure FullScreenDemo(pict1,pict2: GWorldPtr; fadeSpeed: integer);
  1446.  
  1447. Var
  1448.     myErr:            OSErr;
  1449.     theScreen:        GWorldPtr;
  1450.     myPort:            CGrafPtr;
  1451.     savedPort:        CGrafPtr;
  1452.     savedDevice:    GDHandle;
  1453.     
  1454.     begin
  1455.     { If Color QuickDraw is not available, don't do this. }
  1456.     if not HasColorQuickDraw then
  1457.         exit(FullScreenDemo);
  1458.     { Save the current port and device. }
  1459.     GetGWorld(savedPort, savedDevice);
  1460.     { Open a port that covers the main screen. OpenCPort, by default,
  1461.     { makes the port the same size as the main screen. }
  1462.     New(myPort);
  1463.     OpenCPort(myPort);
  1464.     SetGWorld(myPort, NIL);
  1465.     { Make a GWorld to store the current screen picture in. }
  1466.     myErr := NewGWorld(theScreen, 0, myPort^.portRect, NIL, NIL, 0);
  1467.     if myErr <> NoErr then
  1468.         begin
  1469.         CloseCPort(myPort);
  1470.         DoAlertStrID(kAlertDialogID, true, kGWorldErr);
  1471.         ExitToShell;
  1472.         end;
  1473.     { Copy the screen picture into the GWorld. }
  1474.     CopyBits(WinBitMap(myPort), WinBitMap(theScreen),
  1475.             myPort^.portRect, theScreen^.portRect, srcCopy, NIL);
  1476.     { Now fade the screen to black. }
  1477.     FadeToBlack2(WindowPtr(myPort), myPort^.portRect, fadeSpeed);
  1478.     { Slide the first image in from the left. }
  1479.     if not LockPixels(GetGWorldPixMap(pict1)) then;
  1480.     Slide(WindowPtr(pict1), pict1^.portRect,
  1481.         WindowPtr(myPort), myPort^.portRect, fadeSpeed, kLeft);
  1482.     UnlockPixels(GetGWorldPixMap(pict1));
  1483.     { Fade the second image in. }
  1484.     FadeToImage(pict2, pict2^.portRect, WindowPtr(myPort), 
  1485.         myPort^.portRect, fadeSpeed);
  1486.     { Slide the original screen back in from the right. }
  1487.     if not LockPixels(GetGWorldPixMap(theScreen)) then;
  1488.     Slide(WindowPtr(theScreen), theScreen^.portRect,
  1489.         WindowPtr(myPort), myPort^.portRect, fadeSpeed, kRight);
  1490.     UnlockPixels(GetGWorldPixMap(theScreen));
  1491.     { Now get rid of the GWorld we used to hold the screen image. }
  1492.     DisposeGWorld(theScreen);
  1493.     { Close the port. }
  1494.     CloseCPort(myPort);
  1495.     { Restore the saved port and device. }
  1496.     SetGWorld(savedPort, savedDevice);
  1497.     end;
  1498.  
  1499. { DoTechDemo brings up a new dialog that allows you to experiment
  1500. { with all the different ways of using CopyBits, CopyMask, and
  1501. { CopyDeepMask with different source images and masks.
  1502. }
  1503. Procedure DoTechDemo;
  1504.  
  1505. Var
  1506.     demoDlg:        DialogPtr;
  1507.     itemHit:        integer;
  1508.     myEvent:        EventRecord;
  1509.     aDlg:            DialogPtr;
  1510.     sourceRect:        rect;
  1511.     destRect:        rect; 
  1512.     opColorRect:    rect; 
  1513.     maskRect:        rect;
  1514.     maskRegion:        RgnHandle;
  1515.     copyMode:        integer;    { transfer mode }
  1516.     ditherAdd:        integer;
  1517.     hiliteAdd:        integer;
  1518.     saveColor:        RGBColor;
  1519.     tempRect:        rect;
  1520.     maskSet:        Boolean;
  1521.     maskGWorld:        GWorldPtr;    { to hold a pixel map mask }
  1522.     
  1523.     begin
  1524.     { Load the main (only) dialog and display it on screen. This
  1525.     { automatically displays our two source PICTS. Since there is
  1526.     { a 'dctb' (Dialog Color Table) resource with the same ID
  1527.     { as the dialog, the Dialog Manager uses NewColorDialog to
  1528.     { make the dialog, thus giving us a color drawing port. }
  1529.     demoDlg := GetNewDialog(kTechDemoDlgID, NIL, WindowPtr(-1));
  1530.     if demoDlg = NIL then
  1531.         begin
  1532.         DoAlertStrID(kAlertDialogID, true, kMemoryOut);
  1533.         ExitToShell;
  1534.         end;
  1535.     ShowWindow(demoDlg);
  1536.     { Make sure the demo dialog is the current port. }
  1537.     SetGWorld(CGrafPtr(demoDlg), NIL);
  1538.     { Set controls to defaults. }
  1539.     SetRadioButton(demoDlg, kTechDemoSourceFirst,
  1540.         kTechDemoSourceLast, kTechDemoSourceFirst); { first source image }
  1541.     SetRadioButton(demoDlg, kTechDemoMaskFirst,
  1542.         kTechDemoMaskLast, kTechDemoMaskLast);        { no mask image }
  1543.     SetRadioButton(demoDlg, kTechDemoModeFirst,
  1544.         kTechDemoModeLast, kTechDemoModeFirst);    { srcCopy xfer mode }
  1545.     SetOnOff(demoDlg, kTechDemoDither, false);    { no dither }
  1546.     SetOnOff(demoDlg, kTechDemoHilite, false);    { no hilite }
  1547.     SetRadioButton(demoDlg, kTechDemoOpColorFirst,
  1548.         kTechDemoOpColorLast, kTechDemoOpColorLast);    { black OpColor }
  1549.     SetRadioButton(demoDlg, kTechDemoMaskRFirst,
  1550.         kTechDemoMaskRLast, kTechDemoMaskRLast);    { no mask region }
  1551.     { Set default CopyBits parameters. }
  1552.     GetItemRect(demoDlg, kTechDemoSourcePict1, sourceRect);
  1553.     GetItemRect(demoDlg, kTechDemoDestPict, destRect);
  1554.     GetItemRect(demoDlg, kTechDemoOpColorPict, opColorRect);
  1555.     maskSet := false;
  1556.     copyMode := srcCopy;
  1557.     hiliteAdd := 0;
  1558.     ditherAdd := 0;
  1559.     maskRegion := NIL;
  1560.     { Create a GWorld to hold the pixel map mask for CopyMask and CopyDeepMask.
  1561.     { Note that I do this because when I just used the image already in the
  1562.     { dialog (without copying it to its own bitmap), things did not work
  1563.     { correctly. Apparently, the mask has to be in a separate bit/pixmap from
  1564.     { the source and destination images. }
  1565.     SetRect(maskRect, 0, 0, 50, 50);
  1566.     if NewGWorld(maskGWorld, 0, maskRect, NIL, NIL, 0) <> noErr then
  1567.         begin
  1568.         DoAlertStrID(kAlertDialogID, true, kGWorldErr);
  1569.         ExitToShell;
  1570.         end;
  1571.     { Paint the OpColor pict black since that's the default setting. }
  1572.     PaintRect(opColorRect);
  1573.     { Erase the destination rectangle and draw rectangles around the
  1574.     { OpColor, destination, and mask region areas. }
  1575.     EraseRect(destRect);
  1576.     tempRect := destRect;
  1577.     InsetRect(tempRect, -1, -1);
  1578.     FrameRect(tempRect);
  1579.     GetItemRect(demoDlg, kTechDemoOpColorPict, tempRect);
  1580.     InsetRect(tempRect, -1, -1);
  1581.     FrameRect(tempRect);
  1582.     GetItemRect(demoDlg, kTechDemoMaskRPict1, tempRect);
  1583.     InsetRect(tempRect, -1, -1);
  1584.     FrameRect(tempRect);
  1585.     GetItemRect(demoDlg, kTechDemoMaskRPict2, tempRect);
  1586.     InsetRect(tempRect, -1, -1);
  1587.     FrameRect(tempRect);
  1588.     GetItemRect(demoDlg, kTechDemoMaskRPict3, tempRect);
  1589.     InsetRect(tempRect, -1, -1);
  1590.     FrameRect(tempRect);
  1591.     { Draw in the mask regions in the dialog. }
  1592.     DrawMaskRegion(demoDlg, kTechDemoMaskRPict1, 1);
  1593.     DrawMaskRegion(demoDlg, kTechDemoMaskRPict2, 2);
  1594.     DrawMaskRegion(demoDlg, kTechDemoMaskRPict3, 3);
  1595.     { Now wait for the user to press a control in the dialog. }
  1596.     itemHit := -1;
  1597.     while itemHit <> kTechDemoDone do
  1598.         begin
  1599.         if WaitNextEvent(everyEvent, myEvent, GetCaretTime, NIL) then;
  1600.         { Check for disk events (bad disk mount). }
  1601.         if (myEvent.what = diskEvt) and
  1602.             (HiWord(myEvent.message) <> noErr) then
  1603.             Err := DIBadMount(dlgUpLeftCorner, myEvent.message);    { ignore result }
  1604.         { Pass the event to DialogSelect which takes care of tracking
  1605.         { controls and updating everything (except the destination
  1606.         { area) for us. }
  1607.         if DialogSelect(myEvent, aDlg, itemHit) then
  1608.             begin
  1609.             { What we do here depends on what the user clicked }
  1610.             if aDlg = demoDlg then
  1611.                 case itemHit of
  1612.                     { These radio buttons change the source rectangle. }
  1613.                     kTechDemoSourceFirst,
  1614.                     kTechDemoSourcePict1:
  1615.                         begin
  1616.                         SetRadioButton(demoDlg, kTechDemoSourceFirst,
  1617.                             kTechDemoSourceLast, kTechDemoSourceFirst);
  1618.                         GetItemRect(demoDlg, kTechDemoSourcePict1, sourceRect);
  1619.                         end;
  1620.                     kTechDemoSourceFirst+1,
  1621.                     kTechDemoSourcePict2:
  1622.                         begin
  1623.                         SetRadioButton(demoDlg, kTechDemoSourceFirst,
  1624.                             kTechDemoSourceLast, kTechDemoSourceFirst+1);
  1625.                         GetItemRect(demoDlg, kTechDemoSourcePict2, sourceRect);
  1626.                         end;
  1627.                     kTechDemoSourceFirst+2,
  1628.                     kTechDemoSourcePict3:
  1629.                         begin
  1630.                         SetRadioButton(demoDlg, kTechDemoSourceFirst,
  1631.                             kTechDemoSourceLast, kTechDemoSourceFirst+2);
  1632.                         GetItemRect(demoDlg, kTechDemoSourcePict3, sourceRect);
  1633.                         end;
  1634.                     kTechDemoSourceFirst+3,
  1635.                     kTechDemoSourcePict4:
  1636.                         begin
  1637.                         SetRadioButton(demoDlg, kTechDemoSourceFirst,
  1638.                             kTechDemoSourceLast, kTechDemoSourceFirst+3);
  1639.                         GetItemRect(demoDlg, kTechDemoSourcePict4, sourceRect);
  1640.                         end;
  1641.                     kTechDemoSourceLast,
  1642.                     kTechDemoSourcePict5:
  1643.                         begin
  1644.                         SetRadioButton(demoDlg, kTechDemoSourceFirst,
  1645.                             kTechDemoSourceLast, kTechDemoSourceLast);
  1646.                         GetItemRect(demoDlg, kTechDemoSourcePict5, sourceRect);
  1647.                         end;
  1648.                     { These radio buttons change the mask for CopyMask. Each of
  1649.                     { the first three copy the mask image shown in the dialog
  1650.                     { into an offscreen GWorld (maskGWorld) to be used as the mask.
  1651.                     { The fourth is the setting for no mask. }
  1652.                     kTechDemoMaskPict1,
  1653.                     kTechDemoMaskPict2,
  1654.                     kTechDemoMaskPict3,
  1655.                     kTechDemoMaskFirst,
  1656.                     kTechDemoMaskFirst+1,
  1657.                     kTechDemoMaskFirst+2:
  1658.                         begin
  1659.                         if itemHit = kTechDemoMaskPict1 then
  1660.                             itemHit := kTechDemoMaskFirst
  1661.                         else if itemHit = kTechDemoMaskPict2 then
  1662.                             itemHit := kTechDemoMaskFirst+1
  1663.                         else if itemHit = kTechDemoMaskPict3 then
  1664.                             itemHit := kTechDemoMaskFirst+2;
  1665.                         { Set the proper radio button. }
  1666.                         SetRadioButton(demoDlg, kTechDemoMaskFirst,
  1667.                             kTechDemoMaskLast, itemHit);
  1668.                         { Get the rectangle of the selected mask image. }
  1669.                         GetItemRect(demoDlg,
  1670.                             kTechDemoMaskPict1 + itemHit - kTechDemoMaskFirst,
  1671.                             tempRect);
  1672.                         { Lock the mask GWorld's pixels and make it the current port. }
  1673.                         if not LockPixels(GetGWorldPixMap(maskGWorld)) then;
  1674.                         SetGWorld(CGrafPtr(maskGWorld), NIL);
  1675.                         { Copy the mask image from the dialog to the GWorld. } 
  1676.                         CopyBits(WinBitMap(demoDlg), WinBitMap(maskGWorld),
  1677.                             tempRect, maskRect, srcCopy, NIL);
  1678.                         { Make the dialog the current port again. }
  1679.                         SetGWorld(CGrafPtr(demoDlg), NIL);
  1680.                         { Unlock the GWorld's pixels. }
  1681.                         UnlockPixels(GetGWorldPixMap(maskGWorld));
  1682.                         { There is a mask to use. }
  1683.                         maskSet := true;
  1684.                         end;
  1685.                     kTechDemoMaskLast,
  1686.                     kTechDemoMaskNone:
  1687.                         begin
  1688.                         SetRadioButton(demoDlg, kTechDemoMaskFirst,
  1689.                             kTechDemoMaskLast, kTechDemoMaskLast);
  1690.                         maskSet := false;
  1691.                         if maskRegion <> NIL then
  1692.                             begin
  1693.                             DisposeRgn(maskRegion);
  1694.                             maskRegion := NIL;
  1695.                             end;
  1696.                         end;
  1697.                     { These radio buttons change the OpColor. }
  1698.                     kTechDemoOpColorFirst:
  1699.                         begin
  1700.                         SetRadioButton(demoDlg, kTechDemoOpColorFirst,
  1701.                             kTechDemoOpColorLast, kTechDemoOpColorFirst);
  1702.                         OpColor(colors[kWhite]);
  1703.                         GetForeColor(saveColor);
  1704.                         RGBForeColor(colors[kWhite]);
  1705.                         PaintRect(opColorRect);
  1706.                         RGBForeColor(saveColor);
  1707.                         end;
  1708.                     kTechDemoOpColorFirst+1:
  1709.                         begin
  1710.                         SetRadioButton(demoDlg, kTechDemoOpColorFirst,
  1711.                             kTechDemoOpColorLast, kTechDemoOpColorFirst+1);
  1712.                         OpColor(colors[kLtGray]);
  1713.                         GetForeColor(saveColor);
  1714.                         RGBForeColor(colors[kLtGray]);
  1715.                         PaintRect(opColorRect);
  1716.                         RGBForeColor(saveColor);
  1717.                         end;
  1718.                     kTechDemoOpColorFirst+2:
  1719.                         begin
  1720.                         SetRadioButton(demoDlg, kTechDemoOpColorFirst,
  1721.                             kTechDemoOpColorLast, kTechDemoOpColorFirst+2);
  1722.                         OpColor(colors[kGray]);
  1723.                         GetForeColor(saveColor);
  1724.                         RGBForeColor(colors[kGray]);
  1725.                         PaintRect(opColorRect);
  1726.                         RGBForeColor(saveColor);
  1727.                         end;
  1728.                     kTechDemoOpColorFirst+3:
  1729.                         begin
  1730.                         SetRadioButton(demoDlg, kTechDemoOpColorFirst,
  1731.                             kTechDemoOpColorLast, kTechDemoOpColorFirst+3);
  1732.                         OpColor(colors[kDkGray]);
  1733.                         GetForeColor(saveColor);
  1734.                         RGBForeColor(colors[kDkGray]);
  1735.                         PaintRect(opColorRect);
  1736.                         RGBForeColor(saveColor);
  1737.                         end;
  1738.                     kTechDemoOpColorLast:
  1739.                         begin
  1740.                         SetRadioButton(demoDlg, kTechDemoOpColorFirst,
  1741.                             kTechDemoOpColorLast, kTechDemoOpColorLast);
  1742.                         OpColor(colors[kBlack]);
  1743.                         GetForeColor(saveColor);
  1744.                         RGBForeColor(colors[kBlack]);
  1745.                         PaintRect(opColorRect);
  1746.                         RGBForeColor(saveColor);
  1747.                         end;
  1748.                     { These radio buttons change the transfer mode. }
  1749.                     kTechDemoModeFirst:
  1750.                         begin
  1751.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1752.                             kTechDemoModeLast, kTechDemoModeFirst);
  1753.                         copyMode := srcCopy;
  1754.                         end;
  1755.                     kTechDemoModeFirst+1:
  1756.                         begin
  1757.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1758.                             kTechDemoModeLast, kTechDemoModeFirst+1);
  1759.                         copyMode := srcOr;
  1760.                         end;
  1761.                     kTechDemoModeFirst+2:
  1762.                         begin
  1763.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1764.                             kTechDemoModeLast, kTechDemoModeFirst+2);
  1765.                         copyMode := srcXor;
  1766.                         end;
  1767.                     kTechDemoModeFirst+3:
  1768.                         begin
  1769.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1770.                             kTechDemoModeLast, kTechDemoModeFirst+3);
  1771.                         copyMode := srcBic;
  1772.                         end;
  1773.                     kTechDemoModeFirst+4:
  1774.                         begin
  1775.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1776.                             kTechDemoModeLast, kTechDemoModeFirst+4);
  1777.                         copyMode := notSrcCopy;
  1778.                         end;
  1779.                     kTechDemoModeFirst+5:
  1780.                         begin
  1781.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1782.                             kTechDemoModeLast, kTechDemoModeFirst+5);
  1783.                         copyMode := notSrcOr;
  1784.                         end;
  1785.                     kTechDemoModeFirst+6:
  1786.                         begin
  1787.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1788.                             kTechDemoModeLast, kTechDemoModeFirst+6);
  1789.                         copyMode := notSrcXor;
  1790.                         end;
  1791.                     kTechDemoModeFirst+7:
  1792.                         begin
  1793.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1794.                             kTechDemoModeLast, kTechDemoModeFirst+7);
  1795.                         copyMode := notSrcBic;
  1796.                         end;
  1797.                     kTechDemoModeFirst+8:
  1798.                         begin
  1799.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1800.                             kTechDemoModeLast, kTechDemoModeFirst+8);
  1801.                         copyMode := blend;
  1802.                         end;
  1803.                     kTechDemoModeFirst+9:
  1804.                         begin
  1805.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1806.                             kTechDemoModeLast, kTechDemoModeFirst+9);
  1807.                         copyMode := addPin;
  1808.                         end;
  1809.                     kTechDemoModeFirst+10:
  1810.                         begin
  1811.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1812.                             kTechDemoModeLast, kTechDemoModeFirst+10);
  1813.                         copyMode := addOver;
  1814.                         end;
  1815.                     kTechDemoModeFirst+11:
  1816.                         begin
  1817.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1818.                             kTechDemoModeLast, kTechDemoModeFirst+11);
  1819.                         copyMode := subPin;
  1820.                         end;
  1821.                     kTechDemoModeFirst+12:
  1822.                         begin
  1823.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1824.                             kTechDemoModeLast, kTechDemoModeFirst+12);
  1825.                         copyMode := transparent;
  1826.                         end;
  1827.                     kTechDemoModeFirst+13:
  1828.                         begin
  1829.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1830.                             kTechDemoModeLast, kTechDemoModeFirst+13);
  1831.                         copyMode := addMax;
  1832.                         end;
  1833.                     kTechDemoModeFirst+14:
  1834.                         begin
  1835.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1836.                             kTechDemoModeLast, kTechDemoModeFirst+14);
  1837.                         copyMode := subOver;
  1838.                         end;
  1839.                     kTechDemoModeLast:
  1840.                         begin
  1841.                         SetRadioButton(demoDlg, kTechDemoModeFirst,
  1842.                             kTechDemoModeLast, kTechDemoModeLast);
  1843.                         copyMode := adMin;
  1844.                         end;
  1845.                     { These check boxes change the transfer mode. }
  1846.                     kTechDemoDither:
  1847.                         begin
  1848.                         Toggle(demoDlg, kTechDemoDither);
  1849.                         if GetOnOff(demoDlg, kTechDemoDither) then
  1850.                             ditherAdd := ditherCopy
  1851.                         else
  1852.                             ditherAdd := 0;
  1853.                         end;
  1854.                     kTechDemoHilite:
  1855.                         begin
  1856.                         Toggle(demoDlg, kTechDemoHilite);
  1857.                         if GetOnOff(demoDlg, kTechDemoHilite) then
  1858.                             hiliteAdd := hilite
  1859.                         else
  1860.                             hiliteAdd := 0;
  1861.                         end;
  1862.                     { These buttons set the mask region. }
  1863.                     kTechDemoMaskRPict1,
  1864.                     kTechDemoMaskRPict2,
  1865.                     kTechDemoMaskRPict3,
  1866.                     kTechDemoMaskRFirst,
  1867.                     kTechDemoMaskRFirst+1,
  1868.                     kTechDemoMaskRFirst+2:
  1869.                         begin
  1870.                         { Translate clicks on the mask regions to the
  1871.                         { actual radio buttons. }
  1872.                         if itemHit = kTechDemoMaskRPict1 then
  1873.                             itemHit := kTechDemoMaskRFirst
  1874.                         else if itemHit = kTechDemoMaskRPict2 then
  1875.                             itemHit := kTechDemoMaskRFirst+1
  1876.                         else
  1877.                             itemHit := kTechDemoMaskRFirst+2;
  1878.                         SetRadioButton(demoDlg, kTechDemoMaskRFirst,
  1879.                             kTechDemoMaskRLast, itemHit);
  1880.                         if maskRegion <> NIL then
  1881.                             DisposeRgn(maskRegion);
  1882.                         maskRegion := NewRgn;
  1883.                         OpenRgn;
  1884.                         if itemHit = kTechDemoMaskRFirst then
  1885.                             DrawMaskRegion(demoDlg, kTechDemoDestPict, 1)
  1886.                         else if itemHit = kTechDemoMaskRFirst+1 then
  1887.                             DrawMaskRegion(demoDlg, kTechDemoDestPict, 2)
  1888.                         else
  1889.                             DrawMaskRegion(demoDlg, kTechDemoDestPict, 3);
  1890.                         CloseRgn(maskRegion);
  1891.                         end;
  1892.                     kTechDemoMaskRLast,
  1893.                     kTechDemoMaskRNone:
  1894.                         begin
  1895.                         SetRadioButton(demoDlg, kTechDemoMaskRFirst,
  1896.                             kTechDemoMaskRLast, kTechDemoMaskRLast);
  1897.                         DisposeRgn(maskRegion);
  1898.                         maskRegion := NIL;
  1899.                         end;
  1900.                     { These buttons take some action. }
  1901.                     kTechDemoCopyBits:
  1902.                         CopyBits(WinBitMap(demoDlg), WinBitMap(demoDlg),
  1903.                             sourceRect, destRect,
  1904.                             copyMode + ditherAdd + hiliteAdd, maskRegion);
  1905.                     kTechDemoCopyMask:
  1906.                         if maskSet then
  1907.                             begin
  1908.                             { Lock the mask GWorld's pixelMap. }
  1909.                             if not LockPixels(GetGWorldPixMap(maskGWorld)) then;
  1910.                             { CopyMask to the destination. }
  1911.                             CopyMask(WinBitMap(demoDlg),
  1912.                                 WinBitMap(maskGWorld),
  1913.                                 WinBitMap(demoDlg),
  1914.                                 sourceRect, maskRect, destRect);
  1915.                             { Unlock the mask GWorld's pixel map. }
  1916.                             UnlockPixels(GetGWorldPixMap(maskGWorld));
  1917.                             end
  1918.                         else
  1919.                             CopyBits(WinBitMap(demoDlg), WinBitMap(demoDlg), sourceRect, 
  1920.                                 destRect, srcCopy, NIL);
  1921.                     kTechDemoCopyDeepMask:
  1922.                         if maskSet then
  1923.                             begin
  1924.                             { Lock the mask GWorld's pixelMap. }
  1925.                             if not LockPixels(GetGWorldPixMap(maskGWorld)) then;
  1926.                             { CopyDeepMask to the destination. }
  1927.                             CopyDeepMask(WinBitMap(demoDlg),
  1928.                                 WinBitMap(maskGWorld),
  1929.                                 WinBitMap(demoDlg),
  1930.                                 sourceRect, maskRect,
  1931.                                 destRect,
  1932.                                 copyMode + ditherAdd + hiliteAdd,
  1933.                                 maskRegion);
  1934.                             { Unlock the mask GWorld's pixel map. }
  1935.                             UnlockPixels(GetGWorldPixMap(maskGWorld));
  1936.                             end
  1937.                         else
  1938.                             CopyBits(WinBitMap(demoDlg), WinBitMap(demoDlg),
  1939.                                 sourceRect, destRect,
  1940.                                 copyMode + ditherAdd + hiliteAdd, NIL);
  1941.                     kTechDemoErase:
  1942.                         EraseRect(destRect);
  1943.                     kTechDemoDone:
  1944.                         { Close the demo dialog. }
  1945.                         DisposeDialog(demoDlg);
  1946.                     {CASE} end;
  1947.             end;
  1948.         end;
  1949.     { Reset the OpColor to black }
  1950.     OpColor(colors[kBlack]);
  1951.     { Dispose of the maskGWorld. }
  1952.     DisposeGWorld(maskGWorld);
  1953.     { Dispose of the mask region if one was set. }
  1954.     if maskRegion <> NIL then
  1955.         DisposeRgn(maskRegion);
  1956.     end;
  1957.  
  1958. begin
  1959. { Create some colors (white, 3 grays, and black). }
  1960. colors[0].red := $0FFFF;            { white }
  1961. colors[0].green := $0FFFF;
  1962. colors[0].blue := $0FFFF;            
  1963. colors[1].red := trunc($0FFFF * 0.75);    { lt gray }
  1964. colors[1].green := trunc($0FFFF * 0.75);
  1965. colors[1].blue := trunc($0FFFF * 0.75);    
  1966. colors[2].red := trunc($0FFFF * 0.5);    { gray }
  1967. colors[2].green := trunc($0FFFF * 0.5);
  1968. colors[2].blue := trunc($0FFFF * 0.5);    
  1969. colors[3].red := trunc($0FFFF * 0.25);    { dk gray }
  1970. colors[3].green := trunc($0FFFF * 0.25);
  1971. colors[3].blue := trunc($0FFFF * 0.25);    
  1972. colors[4].red := 0;                { black }
  1973. colors[4].green := 0;
  1974. colors[4].blue := 0;    
  1975. { Make sure the main monitor is using a 5 bits per color inverse
  1976. table rather than the default 4. This will make CopyBits
  1977. operations using arithmetic transfer modes a bit more smooth
  1978. (but uses a little more memory). }
  1979. aDevice := GetGDevice;
  1980. SetGDevice(GetMainDevice);
  1981. MakeITable(NIL, NIL, 5);
  1982. SetGDevice(aDevice);
  1983. { Initialize the Mac Toolbox }
  1984. InitToolbox;
  1985. { Check the system version. This project requires System 7
  1986.   or later for the GWorlds.}
  1987. if GetSysVersion < 7 then
  1988.     begin
  1989.     DoAlertStrID(kAlertDialogID, true, kSys7Required);
  1990.     ExitToShell;
  1991.     end;
  1992. {
  1993. { Load the main dialog and display it on screen. This
  1994. { automatically displays our two source PICTS. Since there is
  1995. { a 'dctb' (Dialog Color Table) resource with the same ID
  1996. { as the dialog, the Dialog Manager uses NewColorDialog to
  1997. { make the dialog, thus giving us a color drawing port.
  1998. { In ResEdit, creating a 'dctb' resource for a dialog is as
  1999. { easy as clicking Custom for the color scheme rather than
  2000. { default when you have the 'DLOG' resource open.
  2001. }
  2002. mainDlg:= GetNewDialog(kMainDlgID, NIL, WindowPtr(-1));
  2003. if mainDlg = NIL then
  2004.     begin
  2005.     DoAlertStrID(kAlertDialogID, true, kMemoryOut);
  2006.     ExitToShell;
  2007.     end;
  2008. { Select the text in the fade speed text edit box. }
  2009. SelectTextField(mainDlg, kMainDlgFadeSpeed);
  2010. { Make sure the dialog is visible and that it's the current port. }
  2011. ShowWindow(mainDlg);
  2012. SetGWorld(CGrafPtr(mainDlg), NIL);
  2013. {
  2014. { Get the picture rectangles and the destination picture's
  2015. { rectangle. Save them for later use.
  2016. }
  2017. GetItemRect(mainDlg, kMainDlgPICTOne, pict1Rect);
  2018. GetItemRect(mainDlg, kMainDlgPICTTwo, pict2Rect);
  2019. GetItemRect(mainDlg, kMainDlgDestPICT, destRect);
  2020. {
  2021. { Draw a box around each of the picture areas to better
  2022. { define them on screen.
  2023. }
  2024. tempRect := destRect;
  2025. InsetRect(tempRect, -1, -1);
  2026. FrameRect(tempRect);
  2027. tempRect := pict1Rect;
  2028. InsetRect(tempRect, -1, -1);
  2029. FrameRect(tempRect);
  2030. tempRect := pict2Rect;
  2031. InsetRect(tempRect, -1, -1);
  2032. FrameRect(tempRect);
  2033. {
  2034. { Draw each of the two "source" pictures into an offscreen
  2035. { Graphics World for use later. For example, when the user
  2036. { passes the cursor over the left picture, regular animation
  2037. { techniques are used to make a circle "float" above the
  2038. { picture (causes flicker). This involves repeatedly
  2039. { copying the original picture to the window, then drawing
  2040. { the circle over it. When the user passes the cursor over
  2041. { the right picture, the original picture is drawn to an
  2042. { offscreen gworld and the circle is drawn over it, then
  2043. { that image is drawn to the window resulting in flicker-free
  2044. { animation of the floating circle.
  2045. {
  2046. { We need the two gworlds here so we have the original
  2047. { pictures to copy from.
  2048. { Load picture 1 from resource.
  2049. }
  2050. aPict := GetPicture(kPict1ID);
  2051. if aPict = NIL then
  2052.     begin
  2053.     DoAlertStrID(kAlertDialogID, true, kMissingResource);
  2054.     ExitToShell;
  2055.     end;
  2056. { Get it's optimum rectangle. }
  2057. myErr := GetPictInfo(aPict, myPictInfo, 0, 0, 0, 0);
  2058. pict1GRect := myPictInfo.sourceRect;
  2059. { Release any extra items GetPictInfo may have allocated }
  2060. { if we're not going to use them. }
  2061. if myPictInfo.commentHandle <> NIL then
  2062.     DisposeHandle(Handle(myPictInfo.commentHandle));
  2063. if myPictInfo.fontHandle <> NIL then
  2064.     DisposeHandle(Handle(myPictInfo.fontHandle));
  2065. { Make a GWorld for the picture. }
  2066. myErr := NewGWorld(pict1GWorld, 0, pict1GRect, NIL, NIL, 0);
  2067. if (myErr <> NoErr) | (pict1GWorld = NIL) then
  2068.     begin
  2069.     DoAlertStrID(kAlertDialogID, true, kGWorldErr);
  2070.     ExitToShell;
  2071.     end;
  2072. { Lock the GWorld's pixels and draw the picture into it. }
  2073. if not LockPixels(GetGWorldPixMap(pict1GWorld)) then;
  2074. SetGWorld(CGrafPtr(pict1GWorld), NIL);
  2075. PaintRect(pict1GRect);    { first paint it all black }
  2076. DrawPicture(aPict, pict1GRect);
  2077. UnlockPixels(GetGWorldPixMap(pict1GWorld));
  2078. { Load picture 2 from resource. }
  2079. aPict := GetPicture(kPict2ID);
  2080. if aPict = NIL then
  2081.     begin
  2082.     DoAlertStrID(kAlertDialogID, true, kMissingResource);
  2083.     ExitToShell;
  2084.     end;
  2085. { Get it's optimum rectangle. }
  2086. myErr := GetPictInfo(aPict, myPictInfo, 0, 0, 0, 0);
  2087. pict2GRect := myPictInfo.sourceRect;
  2088. { Release any extra items GetPictInfo may have allocated }
  2089. { if we're not going to use them.  }
  2090. if myPictInfo.commentHandle <> NIL then
  2091.     DisposeHandle(Handle(myPictInfo.commentHandle));
  2092. if myPictInfo.fontHandle <> NIL then
  2093.     DisposeHandle(Handle(myPictInfo.fontHandle));
  2094. { Make a GWorld for the picture. }
  2095. myErr := NewGWorld(pict2GWorld, 0, pict2GRect, NIL, NIL, 0);
  2096. if (myErr <> NoErr) | (pict2GWorld = NIL) then
  2097.     begin;
  2098.     DoAlertStrID(kAlertDialogID, true, kGWorldErr);
  2099.     ExitToShell;
  2100.     end;
  2101. { Lock the GWorld's pixels and draw the picture into it. }
  2102. if not LockPixels(GetGWorldPixMap(pict2GWorld)) then;
  2103. SetGWorld(CGrafPtr(pict2GWorld), NIL);
  2104. PaintRect(pict2GRect);    { first paint it all black }
  2105. DrawPicture(aPict, pict2GRect);
  2106. UnlockPixels(GetGWorldPixMap(pict2GWorld));
  2107. { Make sure and restore the dialog as the current port. }
  2108. SetGWorld(CGrafPtr(mainDlg), NIL);
  2109. { Now wait for the user to press a button in the dialog. }
  2110. itemHit := -1;
  2111. while itemHit <> kMainDlgQuit do
  2112.     begin
  2113.     if WaitNextEvent(everyEvent, myEvent, GetCaretTime(), NIL) then;        
  2114.     { Check for disk events (bad disk mount). }
  2115.     if (myEvent.what = diskEvt) & (HiWord(myEvent.message) <> noErr) then
  2116.         begin
  2117.         SetPt(dlgUpLeftCorner,100,80);
  2118.         Err := DIBadMount(dlgUpLeftCorner, myEvent.message);    { ignore result }
  2119.         end
  2120.     { If we get an update event, redraw the squares around the }
  2121.     { picture areas. }
  2122.     else if (myEvent.what = updateEvt) then
  2123.         begin
  2124.         tempRect := destRect;
  2125.         InsetRect(tempRect, -1, -1);
  2126.         FrameRect(tempRect);
  2127.         tempRect := pict1Rect;
  2128.         InsetRect(tempRect, -1, -1);
  2129.         FrameRect(tempRect);
  2130.         tempRect := pict2Rect;
  2131.         InsetRect(tempRect, -1, -1);
  2132.         FrameRect(tempRect);
  2133.         end;
  2134.     {
  2135.     { If the mouse is over one of the pictures, call a routine
  2136.     { to animate a "floating circle" over the picture. A
  2137.     { different method is used for each picture to demonstrate
  2138.     { the differences.
  2139.     }
  2140.     GetMouse(mouseLoc);
  2141.     if PtInRect(mouseLoc, pict1Rect)  then
  2142.         FlickerAnimate(pict1GWorld, pict1Rect)
  2143.     else if PtInRect(mouseLoc, pict2Rect) then
  2144.         SmoothAnimate(pict2GWorld, pict2Rect);
  2145.     {
  2146.     { Pass the event to DialogSelect which takes care of tracking
  2147.     { controls and updating everything (except the destination
  2148.     { area) for us.
  2149.     }
  2150.     if DialogSelect(myEvent, aDlg, itemHit) then
  2151.         begin
  2152.         if myEvent.what = mouseDown then
  2153.             begin
  2154.             { Select the fade speed text field. }
  2155.             SelectTextField(mainDlg, kMainDlgFadeSpeed);
  2156.             { Get the fade speed from the dialog (as a number). }
  2157.             fadeSpeed := GetDialogNumberField(mainDlg, kMainDlgFadeSpeed);
  2158.             end;
  2159.         { What we do here depends on what the user clicked }
  2160.         case itemHit of
  2161.             kMainDlgCopyOne:
  2162.                 begin
  2163.                 {
  2164.                 { This is an example of a very courteous CopyBits
  2165.                 { operation saving and restoring the pen state as
  2166.                 { well as the fore and background colors and restoring
  2167.                 { them afterwards. I don't really need to do this here
  2168.                 { because I know they're all set right in the first
  2169.                 { place, but they're here as an example.
  2170.                 
  2171.                 { Save the pen state and foreground/background colors
  2172.                 }
  2173.                 GetPenState(savedPen);
  2174.                 GetForeColor(savedFore);
  2175.                 GetBackColor(savedBack);
  2176.                 { Set foreground color to black, background color to white }
  2177.                 RGBForeColor(colors[kBlack]);
  2178.                 RGBBackColor(colors[kWhite]);
  2179.                 { Just use CopyBits to copy the PICT. We're actually }
  2180.                 { copying from one place on the dialog to another here. }
  2181.                 CopyBits(WinBitMap(mainDlg), WinBitMap(mainDlg),
  2182.                     pict1Rect, destRect, srcCopy, NIL);
  2183.                 { Restore the saved pen state and colors }
  2184.                 SetPenState(savedPen);
  2185.                 RGBForeColor(savedFore);
  2186.                 RGBBackColor(savedBack);
  2187.                 end;    
  2188.             kMainDlgFadeOne:
  2189.                 { Call FadeToImage to fade picture 1 into the }
  2190.                 { destination area. }
  2191.                 FadeToImage(pict1GWorld, pict1GWorld^.portRect,
  2192.                     mainDlg, destRect, fadeSpeed);
  2193.             kMainDlgCopyTwo:
  2194.                 { Just use CopyBits to copy the PICT from one place in }
  2195.                 { the window to another. }
  2196.                     CopyBits(WinBitMap(mainDlg), WinBitMap(mainDlg),
  2197.                         pict2Rect, destRect, srcCopy, NIL);
  2198.             kMainDlgFadeTwo:
  2199.                 { Call FadeToImage to fade picture 2 into the }
  2200.                 { destination area. }
  2201.                 FadeToImage(pict2GWorld, pict2GWorld^.portRect,
  2202.                     mainDlg, destRect, fadeSpeed);
  2203.             kMainDlgErase:
  2204.                 { Erase the destination area. }
  2205.                 EraseRect(destRect);
  2206.             kMainDlgFadeToBlack1:
  2207.                 { Call FadeToBlack to fade the destination rectangle. }
  2208.                 FadeToBlack1(mainDlg, destRect, fadeSpeed);
  2209.             kMainDlgFadeToBlack2:
  2210.                 { Call FadeToBlack to fade the destination rectangle. }
  2211.                 FadeToBlack2(mainDlg, destRect, fadeSpeed);
  2212.             kMainDlgFadeToBlack3:
  2213.                 { Call FadeToBlack to fade the destination rectangle. }
  2214.                 FadeToBlack3(mainDlg, destRect, fadeSpeed);
  2215.             kMainDlgPixelize:
  2216.                 { Call Pixelize. }
  2217.                 Pixelize(mainDlg, destRect,
  2218.                     mainDlg, destRect, fadeSpeed, true);
  2219.             kMainDlgDepixelizeOne:
  2220.                 begin
  2221.                 { Call Pixelize. }
  2222.                 if not LockPixels(GetGWorldPixMap(pict1GWorld)) then;
  2223.                 Pixelize(WindowPtr(pict1GWorld), pict1GWorld^.portRect,
  2224.                     mainDlg, destRect, fadeSpeed, false);
  2225.                 UnlockPixels(GetGWorldPixMap(pict1GWorld));
  2226.                 end;
  2227.             kMainDlgDepixelizeTwo:
  2228.                 begin
  2229.                 { Call Pixelize. }
  2230.                 if not LockPixels(GetGWorldPixMap(pict2GWorld)) then;
  2231.                 Pixelize(WindowPtr(pict2GWorld), pict2GWorld^.portRect,
  2232.                     mainDlg, destRect, fadeSpeed, false);
  2233.                 UnlockPixels(GetGWorldPixMap(pict2GWorld));
  2234.                 end;
  2235.             kMainDlgFullScreen:
  2236.                 { Fade full screen to black, then image 1, then image 2, }
  2237.                 { then back to original. }
  2238.                 FullScreenDemo(pict1GWorld, pict2GWorld, fadeSpeed);
  2239.             kMainDlgBlur:
  2240.                 { Blur the destination area. }
  2241.                 Blur(WindowPtr(mainDlg), destRect);
  2242.             kMainDlgFlipHoriz:
  2243.                 { Flip the destination area horizontally. }
  2244.                 FlipHorizontal(WindowPtr(mainDlg), destRect);
  2245.             kMainDlgFlipVert:
  2246.                 { Flip the destination area horizontally. }
  2247.                 FlipVertical(WindowPtr(mainDlg), destRect);
  2248.             kMainDlgSlideL:
  2249.                 begin
  2250.                 { Slide picture one into destination from left. }
  2251.                 if not LockPixels(GetGWorldPixMap(pict1GWorld)) then;
  2252.                 Slide(WindowPtr(pict1GWorld), pict1GWorld^.portRect,
  2253.                     mainDlg, destRect, fadeSpeed, kLeft);
  2254.                 UnlockPixels(GetGWorldPixMap(pict1GWorld));
  2255.                 end;
  2256.             kMainDlgSlideR:
  2257.                 begin
  2258.                 { Slide picture one into destination from right. }
  2259.                 if not LockPixels(GetGWorldPixMap(pict1GWorld)) then;
  2260.                 Slide(WindowPtr(pict1GWorld), pict1GWorld^.portRect,
  2261.                     mainDlg, destRect, fadeSpeed, kRight);
  2262.                 UnlockPixels(GetGWorldPixMap(pict1GWorld));
  2263.                 end;
  2264.             kMainDlgSlideT:
  2265.                 begin
  2266.                 { Slide picture one into destination from top. }
  2267.                 if not LockPixels(GetGWorldPixMap(pict1GWorld)) then;
  2268.                 Slide(WindowPtr(pict1GWorld), pict1GWorld^.portRect,
  2269.                     mainDlg, destRect, fadeSpeed, kTop);
  2270.                 UnlockPixels(GetGWorldPixMap(pict1GWorld));
  2271.                 end;
  2272.             kMainDlgSlideB:
  2273.                 begin
  2274.                 { Slide picture one into destination from bottom. }
  2275.                 if not LockPixels(GetGWorldPixMap(pict1GWorld)) then;
  2276.                 Slide(WindowPtr(pict1GWorld), pict1GWorld^.portRect,
  2277.                     mainDlg, destRect, fadeSpeed, kBottom);
  2278.                 UnlockPixels(GetGWorldPixMap(pict1GWorld));
  2279.                 end;
  2280.             kMainDlgApertureIn:
  2281.                 begin
  2282.                 { Close a circle in on the destination revealing }
  2283.                 { picture two outside the circle. }
  2284.                 if not LockPixels(GetGWorldPixMap(pict2GWorld)) then;
  2285.                 Aperture(WindowPtr(pict2GWorld), pict2GWorld^.portRect,
  2286.                     mainDlg, destRect, fadeSpeed, kIn);
  2287.                 UnlockPixels(GetGWorldPixMap(pict2GWorld));
  2288.                 end;
  2289.             kMainDlgApertureOut:
  2290.                 begin
  2291.                 { Open a circle out on the destination revealing }
  2292.                 { picture two inside the circle. }
  2293.                 if not LockPixels(GetGWorldPixMap(pict2GWorld)) then;
  2294.                 Aperture(WindowPtr(pict2GWorld), pict2GWorld^.portRect,
  2295.                     mainDlg, destRect, fadeSpeed, kOut);
  2296.                 UnlockPixels(GetGWorldPixMap(pict2GWorld));
  2297.                 end;
  2298.             kMainDlgTechDemo:
  2299.                 begin
  2300.                 { Open the technical demo window and let the user mess around. }
  2301.                 DoTechDemo;
  2302.                 { Make sure the current port is set back to the main dialog. }
  2303.                 SetGWorld(CGrafPtr(mainDlg), NIL);
  2304.                 end;
  2305.         {CASE}    end;
  2306.         end;
  2307.     end;
  2308. { Get rid of the main dialog. }
  2309. DisposeDialog(mainDlg); 
  2310. { Restore the main monitor's inverse table to 4 bits per }
  2311. { color (which is the default). }
  2312. aDevice := GetGDevice;
  2313. SetGDevice(GetMainDevice());
  2314. MakeITable(NIL, NIL, 4);
  2315. SetGDevice(aDevice);
  2316. end.
  2317.  
  2318.